Sie haben die Ausnahme-Stack-Trace nicht schreiben, aber ich erwarte, dass es etwas so aussah:
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
Wir können sehen, dass die Ausnahme von der Control.Handle
Getter-Eigenschaft ausgelöst. Und in der Tat, wenn wir an den source code für diese Eigenschaft schauen, da ist es, wie erwartet:
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
Der interessante Teil ist, wenn wir den Code anschauen, die Control.Handle
aufruft. In diesem Fall ist, dass die Control.WindowText Set-Eigenschaft:
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;
}
}
}
}
Beachten Sie, dass die Handle
Eigenschaft wird nur aufgerufen, wenn IsHandleCreated
true
ist.
Und für die Vollständigkeit, wenn wir den Code für IsHandleCreated betrachten, sehen wir folgende:
public bool IsHandleCreated {
get { return window.Handle != IntPtr.Zero; }
}
der Grund, warum Sie nicht die Ausnahme erhalten, ist, weil also durch die Zeit, die Task
ausgeführt wird, die Fensterhandle wurde noch nicht erstellt, was zu erwarten ist, da die Task
im Konstruktor des Formulars beginnt, dh bevor das Formular angezeigt wird.
Bevor das Fensterhandle erstellt wird, erfordert das Ändern einer Eigenschaft noch keine Arbeit vom UI-Thread. Während dieses kleinen Zeitfensters zu Beginn des Programms scheint es also möglich zu sein, die Methoden auf Steuerinstanzen von einem Nicht-UI-Thread aufzurufen, ohne die "Cross-Thread" -Ausnahme zu erhalten. Aber klar, die Existenz dieses speziellen kleinen Zeitfensters ändert nichts an der Tatsache, dass wir immer sicherstellen sollten, Kontrollmethoden aus dem UI-Thread als sicher aufzurufen.
Um zu beweisen, dass das Timing der Fensterhandle-Erstellung ausschlaggebend dafür ist, die "cross thread" -Ausnahme zu erhalten, versuchen Sie, das Beispiel zu ändern, um die Erstellung des Fensterhandle zu erzwingen und beachten Sie, wie Sie wird nun konsequent die erwartete Ausnahme erhalten, auch ohne Schlaf:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Force creation of window handle
var dummy = txtHello.Handle;
Task.Run(() =>
{
txtHello.Text = "Hello"; // kaboom
});
}
}
Relevante Dokumentation: Control.Handle
Wenn der Griff wurde noch nicht erstellt wurde, diese Eigenschaft verweist zwingen wird, die Griff erstellt werden.
Das wird für mich auch eine Überraschung sein, wenn es wahr ist! –