Möglicherweise erstellen Sie Ihre Steuerelemente im falschen Thread. Beachten Sie die folgende Dokumentation von MSDN :
Dies bedeutet, dass InvokeRequired false zurückgeben kann, wenn Invoke nicht erforderlich ist (der Aufruf erfolgt im selben Thread) oder wenn das Steuerelement in einem anderen Thread erstellt wurde, das Handle des Steuerelements jedoch noch nicht erstellt wurde.
Wenn das Handle des Steuerelements noch nicht erstellt wurde, sollten Sie nicht einfach Eigenschaften, Methoden oder Ereignisse für das Steuerelement aufrufen. Dies kann dazu führen, dass das Handle des Steuerelements im Hintergrundthread erstellt wird, wodurch das Steuerelement in einem Thread ohne Nachrichtenpumpe isoliert wird und die Anwendung instabil wird.
Sie können sich vor diesem Fall schützen, indem Sie auch den Wert von IsHandleCreated überprüfen, wenn InvokeRequired in einem Hintergrundthread false zurückgibt. Wenn das Steuerelement noch nicht erstellt wurde, müssen Sie warten, bis es erstellt wurde, bevor Sie Invoke oder BeginInvoke aufrufen. Dies geschieht normalerweise nur, wenn im Konstruktor des primären Formulars für die Anwendung ein Hintergrundthread erstellt wird (wie in Application.Run (neues MainForm ()), bevor das Formular angezeigt oder Application.Run aufgerufen wurde.
Mal sehen, was das für Sie bedeutet. (Dies wäre leichter zu begründen, wenn wir auch Ihre Implementierung von SafeInvoke sehen würden.)
Angenommen, Ihre Implementierung ist mit der referenzierten identisch, mit Ausnahme der Prüfung gegen IsHandleCreated , folgen wir der Logik:
public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
{
if (uiElement == null)
{
throw new ArgumentNullException("uiElement");
}
if (uiElement.InvokeRequired)
{
if (forceSynchronous)
{
uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
else
{
uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
}
else
{
if (uiElement.IsDisposed)
{
throw new ObjectDisposedException("Control is already disposed.");
}
updater();
}
}
Stellen Sie sich den Fall vor, in dem wir SafeInvoke
vom Nicht-GUI-Thread nach einem Steuerelement rufen, dessen Handle nicht erstellt wurde.
uiElement
ist nicht null, also prüfen wir uiElement.InvokeRequired
. Gemäß den MSDN-Dokumenten (fett gedruckt) InvokeRequired
wird zurückgegeben, false
da das Handle nicht erstellt wurde, obwohl es in einem anderen Thread erstellt wurde! Dies versetzt uns in den else
Zustand, in dem wir IsDisposed
die übermittelte Aktion überprüfen oder sofort aufrufen ... aus dem Hintergrund-Thread !
Zu diesem Zeitpunkt sind alle Wetten für dieses Steuerelement deaktiviert, da sein Handle für einen Thread erstellt wurde, für den keine Nachrichtenpumpe vorhanden ist, wie im zweiten Absatz erwähnt. Vielleicht ist dies der Fall, dem Sie begegnen?