2015-06-15 13 views
8

Ich bekomme immer Fehlermeldung von "Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, weil ein anderer Thread es besitzt." online "itw.show();" wenn diese Funktion zweimal aufgerufen wird. Es funktioniert gut für den ersten Anruf, und nachdem das Fenster geschlossen ist und versucht, erneut zu öffnen, schlägt es fehl. Da ich die Methode "Invoke" auskommentiert habe, funktioniert sie auch nicht mit dem Dispatcher. Bitte helfen Sie mir, die Lösung zu finden. Danke.WPF neues Fenster erstellen auf neuen Thread Fehler

----------------- bearbeiten

Der Grund, warum ich einen neuen Thread bin zu schaffen ist, weil es ein Excel Addin ist. Ich kann keine Fenster aus dem Hauptthread erstellen, das ist das Excel, das mit Windows kollidiert, wenn ich sie vom Hauptthread erstelle.
Die Sache, die ich nicht verstehe, ist, dass warum die neue Instanz (ItemWindow) von neuen Thread mit alten Thread kollidiert.

+2

Warum möchten Sie einen neuen Thread erstellen, um dieses Fenster anzuzeigen? Dies ist im Allgemeinen keine gute Idee. Und zweitens habe ich das versucht und es funktioniert gut (außer ich habe keine Ahnung was "LoginCheck" tut). Wo tritt die Ausnahme auf? –

+2

Der gesamte Code für die Benutzeroberfläche muss im Hauptthread ausgeführt werden. Was versuchst du hier zu erreichen? – almulo

+0

Normalerweise bezieht sich dieser Fehler darauf, dass Sie versuchen, auf eine Eigenschaft in Ihrem ersten Formular zuzugreifen, von der, die Sie abgeschnürt haben. Wir müssten tatsächlich sehen, was auf dem zweiten Formular passiert, das das Problem verursacht. – DoomVroom

Antwort

0

Ich erstellte eine einfache Testmethode in einer neuen Anwendung, die aufgerufen wird, wenn ich auf die Schaltfläche (nur) auf meinem Hauptformular klicke. Das Verfahren sieht wie folgt aus:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Thread thread = new Thread(() => 
    { 
     Window1 window = new Window1(); 
     window.Closed += (s, a) => window.Dispatcher.InvokeShutdown(); 
     window.Show(); 
     System.Windows.Threading.Dispatcher.Run(); 
    }); 

    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
} 

Window1 ist ein Fenster der Klasse I gemacht, dass nichts anderes als eine einzige TextBlock drauf hat. Ich kann so oft auf diese Schaltfläche klicken, und es öffnet weiterhin neue Fenster ohne Probleme (unabhängig davon, ob ich die vorherige zuerst schließe).

Ich vermute, dass das Problem im Code auftritt, dass Sie uns nicht irgendwo zeigen. Sie müssen sehr vorsichtig sein, dass nichts in Ihrem neuen Thread versucht, auf irgendeine Benutzeroberfläche zuzugreifen, die sich auf Ihren Hauptthread bezieht. Windows, die auf separaten Threads ausgeführt werden, können nicht miteinander kommunizieren, es sei denn, sie durchlaufen den Dispatcher des anderen Threads. Die Ausnahme, die Sie sehen, wird ausgelöst, wenn auf eine Methode oder Eigenschaft eines DispatcherObject von einem anderen Thread als dem, der das Objekt erstellt hat, zugegriffen wird.

Einen Schritt zurück, warum ist es wichtig, dass das neue Fenster auf einem eigenen Thread ist? Wenn das neue Fenster den Thread nicht monopolisiert, wird es wahrscheinlich auf dem Hauptthread gut laufen. Wenn Sie eine lange blockierende Operation ausführen, sollte diese Operation möglicherweise nur in einen Thread und nicht in das gesamte Fenster verschoben werden. Ich weiß nicht, was du genau machst, aber es ist etwas, über das du nachdenken solltest.


EDIT: Die Erkenntnis, dass Sie nicht in einer typischen WPF-Anwendung ausgeführt werden können (sieht aus wie Sie in einer Office-Plugin sein könnten), ich meine Prüfung aktualisierte die Fenster vollständig auf ihre eigenen Threads Standalone zu starten. Ich bin jedoch immer noch in der Lage, zwei Fenster hintereinander ohne Probleme zu starten.

Hier ist mein neuer Test. Diese Methode und die Testklasse Window1 sind die Gesamtheit meiner Anwendung.

[STAThread] 
public static int Main(string[] args) 
{ 
    ThreadStart threadFunc =() => 
    { 
     Window1 window = new Window1(); 
     window.Closed += (s, a) => window.Dispatcher.InvokeShutdown(); 
     window.Show(); 
     System.Windows.Threading.Dispatcher.Run(); 
    }; 

    Thread thread = new Thread(threadFunc); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    thread.Join(); 

    thread = new Thread(threadFunc); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    thread.Join(); 

    return 0; 
} 

So scheint es nichts falsch mit dem, was Sie zu tun versuchen, noch sehe ich offensichtliches Problem in Ihrem Code. Ich vermute, dass irgendwo in Ihrem benutzerdefinierten Fenster eine ungültige Cross-Thread-Kommunikation stattfindet, während sie angezeigt wird. (Entweder das oder ein Problem mit Office-Plugins.)

+0

Ich denke es hat etwas mit Excel zu tun. Was ich nicht verstehe ist, warum die neue Instanz (ItemWindow) aus dem neuen Thread mit dem alten Thread kollidiert. – icewall

+0

Haben Sie sich den Callstack der Exception angesehen? Vielleicht wird es einige Hinweise darüber geben, was den ungültigen Anruf verursacht. Sie können auch die Debugger-Option "Just My Code" deaktivieren, um den vollständigen Aufrufstack (einschließlich Methoden von externen Assemblys) im Fenster "Call Stack" in Visual Studio anzuzeigen. – Xavier

0

Sie versuchen, den Ereignishandler mit dem ItemWindow zu verbinden, nachdem bereits sichtbar ist.

Sie müssen den Auftrag wechseln aus:

ItemWindow itw = new ItemWindow(); 
itw.Show(); 
itw.Closed += (sender2, e2) => { itw.Dispatcher.InvokeShutdown(); }; 

zu

ItemWindow itw = new ItemWindow(); 
itw.Closed += (sender2, e2) => { itw.Dispatcher.InvokeShutdown(); }; 
itw.Show(); 
-1

Eine mögliche Ursache sind Abhängigkeitseigenschaften. Abhängigkeitseigenschaften sind ein wenig wählerisch, wenn es um das Threading geht.

Auch wenn Sie nicht Ihre eigenen DepProps definieren, wird Ihr Fenster immer noch einige haben und es gibt keine Möglichkeit, sie loszuwerden.

DepProps haben einen erheblichen Nachteil: Sie sind fadengebunden und können nicht von einem anderen Thread aus aufgerufen werden. Welcher Thread alle Rechte enthält, wird durch den Thread definiert, der die DepProps initialisiert, in Ihrem Fall der erste Aufruf an new ItemWindow(). Nach diesem ersten Aufruf wird Ihr Thread festgelegt und Sie benötigen diesen Thread, um auf Ihre DepProps zuzugreifen.

Für das erste Fenster ist das kein Problem, aber das zweite hatte eindeutig einen anderen Thread. Ich weiß nicht genau, wie DepProps das macht, aber Sie könnten versuchen, den Synchronisationskontext des ersten Threads zu erfassen und wiederherzustellen. Eine andere Option wäre, den Dispatcher des ersten Threads (nicht den Hauptthread) zu erfassen.

Verwandte Themen