Вы не отправляли стек исключений трассировки, но я ожидаю, что это выглядело примерно так:
System.InvalidOperationException: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.set_WindowText(String value)
at System.Windows.Forms.TextBoxBase.set_WindowText(String value)
at System.Windows.Forms.Control.set_Text(String value)
at System.Windows.Forms.TextBoxBase.set_Text(String value)
at System.Windows.Forms.TextBox.set_Text(String value)
at WindowsFormsApplicationcSharp2015.Form1.<.ctor>b__0_0() in D:\test\WindowsFormsApplicationcSharp2015\Form1.cs:line 27
Мы можем видеть, что исключение из свойства Control.Handle
геттера. И в самом деле, если мы посмотрим на source code для этого свойства, там, как и ожидалось:
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
Самое интересное, когда мы смотрим на код, который вызывает Control.Handle
. В этом случае, это свойство Control.WindowText сеттера:
set {
if (value == null) value = "";
if (!WindowText.Equals(value)) {
if (IsHandleCreated) {
UnsafeNativeMethods.SetWindowText(new HandleRef(window, Handle), value);
}
else {
if (value.Length == 0) {
text = null;
}
else {
text = value;
}
}
}
}
Обратите внимание, что Handle
свойства вызывается только если IsHandleCreated
является true
.
И для полноты картины, если мы посмотрим на код для IsHandleCreated мы видим следующее:
public bool IsHandleCreated {
get { return window.Handle != IntPtr.Zero; }
}
Таким образом, по этой причине вы не получите исключение, потому, что к тому времени Task
исполняет, то оконный дескриптор еще не создан, что следует ожидать, так как Task
начинается в конструкторе формы, то есть до отображения формы.
Прежде чем дескриптор окна будет создан, изменение свойства еще не требует какой-либо работы из потока пользовательского интерфейса. Поэтому во время этого небольшого временного окна в начале вашей программы, казалось бы, можно вызвать методы из экземпляров управления из потока, отличного от UI, без исключения «кросс-потока». Но, очевидно, существование этого особого маленького временного окна не меняет того факта, что мы всегда должны обязательно использовать методы управления из потока пользовательского интерфейса для обеспечения безопасности.
Чтобы доказать, что время создания дескриптора окна является определяющим фактором при получении (или нет) исключения «кросс-потока», попробуйте изменить свой пример, чтобы принудительно создать дескриптор окна перед тем, как запустить задачу и обратите внимание, как вы теперь будете последовательно получить ожидаемое исключение, даже без сна:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Force creation of window handle
var dummy = txtHello.Handle;
Task.Run(() =>
{
txtHello.Text = "Hello"; // kaboom
});
}
}
Соответствующая документация: Control.Handle
Если ручка еще не была создана, ссылки это свойство будет принудительно который будет создан.
Это станет для меня неожиданностью, если это правда! –