Ich habe einige Threading-Probleme mit einer großen App, an der ich gerade arbeite (Cross-Thread-Ausnahmen erhalten). Gibt es eine Möglichkeit, den Thread-Namen/ID, auf dem ein bestimmtes Steuerelement erstellt wurde, zu finden?Gibt es eine Möglichkeit, den Besitzer-Thread eines Steuerelements zu finden?
Der Fehler tritt auf, wenn ich ein neues Steuerelement der Steuerelementkollektion meines Steuerelements hinzufügen möchte. Ich kann nicht wirklich ein kleines, reproduzierbares Sample erstellen, also werde ich es so gut wie möglich beschreiben.
Ich habe ein Hauptsteuerelement, das auf einem Formular sitzt, nennen Sie es _mainControl. In seinem Konstruktor instanziiert ich eine Instanz einer anderen Steuerung, so etwas wie
ChildControl _childControl = new ChildControl();
Jetzt _childControl existiert, aber ich füge es nicht zu _mainControls Sammlung noch.
Schließlich erhält _mainControl eine Ereignisbenachrichtigung, dass ich das Steuerelement hinzufügen sollte. Ich überprüfen, ob this.InvokeRequired im Ereignishandler und wenn es ist, rufe ich den Handler, etwa wie folgt:
AddControlEventHander(...)
{
if(InvokeRequired)
{
BeginInvoke(new MethodInvoker(AddControlEventHander);
return;
}
Controls.Add(_childControl);
}
Die Ausnahme immer auf Controls.Add ("Cross-Thread-Betrieb nicht gültig geworfen wird: Kontrollieren Sie '_item', auf das von einem anderen Thread als dem Thread zugegriffen wurde, auf dem es erstellt wurde ").
Nun, was ich nicht verstehe, ist, wie das möglich ist. Ich habe _childControl für denselben Thread erstellt, auf dem _mainControl erstellt wurde. Wenn ich das Threads-Fenster während des Debuggens anschaue, ist der aktuelle Thread-Name/ID derselbe, wenn ich Control.Add so aufrufe, wie es war, als das _childControl hinzugefügt wurde. Die Sache, die mich am meisten verwirrt, sind die folgenden Aufrufe von _mainControl:
Wie ist das möglich? Ist es möglich, dass _childControl in einem Thread erstellt wird, während seine Children irgendwie auf einem anderen erstellt werden? Alle untergeordneten childControl-Objekte werden während der Initialisierung wie normalerweise erstellt.
Wenn jemand irgendwelche Tipps/Vorschläge hat, was passieren könnte, lass es mich wissen.
Danke.
Edit:
Falls jemand interessiert ist, fand ich heraus, was los war. Ich war neugierig, wie ein Steuerelement in einem Thread erstellt werden kann und dass untergeordnete Elemente in einem anderen Thread erstellt werden, obwohl die InitializeComponent-Komponente in demselben Thread ausgeführt wurde. Also habe ich herausgefunden, in welchem Thread das Kind erstellt wurde, indem er einen Code verwendet, der ähnlich dem ist, was Charles unten vorgeschlagen hat. Sobald ich das wusste, wusste ich zumindest, auf welchen Thread ich mich konzentrieren sollte. Dann habe ich das OnHandleCreated-Ereignis der Kindersicherung abgebrochen und das Problem gefunden.
Eine Sache, die ich nicht wusste war, dass das Handle eines Steuerelements erstellt wird, wenn das Steuerelement zuerst sichtbar gemacht wird, nicht wenn es erstellt wird. Ein Thread, dem das Steuerelement nicht gehörte, versuchte also, seine Sichtbarkeit auf "wahr" zu setzen. Also fügte ich einen Check hinzu, um zu sehen, ob InvokeRequired und dachte, dass das den Trick machen würde. Etwas, das ich wirklich nicht erwartet habe, ist, dass das Aufrufen von InvokeRequired das Handle des Steuerelements erstellt, wenn es noch nicht erstellt wurde! Dies führt dazu, dass das Steuerelement im falschen Thread erstellt wird und für InvokeRequired immer den Wert false zurückgibt. Ich habe dies durch Berühren der Handle-Eigenschaft des Steuerelements gelöst, sodass es erstellt wird, bevor InvokeRequired aufgerufen wird.
Vielen Dank für die Hilfe Jungs :)
Vielen Dank für den Hinweis. Ich entdeckte ebenfalls, dass das harmlose 'if (control.Handle! = Null) ... 'tatsächlich die Kontrolle über diesen Thread erzeugt! –
Siehe meine Antwort hier http://stackoverflow.com/questions/8331144/ensuring-that-child-controls-are-created-in-main-ui-thread/17054689#17054689 –