Ich habe eine Menge Möglichkeiten ausprobiert, um eine statische Referenz meines Fensters über mein Programm zu erhalten. Ich muss auf alle seine Mitglieder zur Laufzeit von verschiedenen Klassen zugreifen, so dass eine statische Referenz benötigt wird.
Was ich gerne hätte, wäre etwas wie Program.Window1
, wobei Core
statisch ist und MyWindow
eines seiner statischen Mitglieder ist.
In WinForms deklariere ich normalerweise mein statisches Formular in Program.cs, aber das scheint nicht mit WPF und ihrer benutzerdefinierten "App.xaml" ApplicationDefinition zu funktionieren.
Wie kann ich es tun?
Hinweis: Ich habe bereits eine Reihe von Möglichkeiten ausprobiert: Einen direkten Aufruf eines neuen Fensters zu verwenden (d. h. Program.Window1 = new Window1()
) funktioniert nicht, da ich eine Thread-Invaliditäts-Ausnahme erhalte. Wie ich bisher verstanden habe, kann nur ApplicationDefinitions Windows in WPF starten.
Hier ist die Ausnahme, wenn ich versuche, ein Fenster "nach Code" zu erstellen und nicht nach dem StartupUri der XAML ApplicationDefinition:
Der aufrufende Thread muss STA sein, da viele UI-Komponenten dies erfordern.
Erstellen Sie eine statische Klasse, die das Fensterobjekt enthalten kann, und wenn das Fenster erstellt wird, übergibt es sich selbst an die statische Klasse. Von da an kann die statische Klasse das Fensterobjekt an interessierte Parteien übergeben, obwohl das Fenster angezeigt wird Objekt selbst ist nicht statisch. Etwas wie das. Ihr Formular muss nicht statisch sein, Sie brauchen nur einen statischen Platz, um das Formularobjekt zu halten.
%Vor%Versuchen Sie Folgendes ((MainWindow) App.Current.Windows [0]). MainCanvas.
Es ist absolut möglich, eigene Fenster mit WPF zu instanziieren. Aber ja, Sie müssten auf dem "UI-Thread" sein (was ein STA-Thread ist).
Sagen wir beispielsweise, dass wir eine Eigenschaft in unserer App-Klasse haben möchten, die ein Fenster freilegt.
%Vor% Das Problem mit diesem Code ist, wie Sie erfahren haben, abhängig davon, welcher Thread den MyWindow-Getter aufruft, new Window1()
wird fehlschlagen, wenn der Thread keine STA ist.
Um sicherzustellen, dass das Fenster im rechten Thread erstellt wird, geben Sie das Dispatcher-Objekt . Dieses Objekt wird in WPF verwendet, um sicherzustellen, dass die Kommunikation zwischen UI-Elementen im richtigen Thread erfolgt.
Zurück zu unserem new Window1
, können wir das App.Dispatcher-Objekt verwenden, um sicherzustellen, dass die Operation new
im Hauptanwendungs-Thread wie folgt ausgeführt wird:
Hier halte ich das Dispatcher-Objekt der aktuellen Anwendung fest und rufe Invoke
mit einem Delegaten auf, der den eigentlichen Neustart durchführt. Invoke
stellt sicher, dass mein Delegat im richtigen Thread ausgeführt wird, und gibt das Ergebnis zurück. Voila, das Fenster wird ohne den gefürchteten STA-Fehler erstellt.
Nun müssen Sie daran denken, dass weitere Aufrufe der MyWindow-Instanz auch für den richtigen Thread ausgeführt werden müssen. Um zu vermeiden, dass Ihr Code mit Aufrufen von Dispatcher.Invoke verschmutzt wird, könnte es nützlich sein, die Fensterinstanz hinter einer einfachen API zu verpacken. Z.B. Eine Show-Methode könnte so implementiert werden, dass der Show-Aufruf über das Dispatcher-Objekt des Fensters verwaltet wird:
%Vor%Ich habe das mit Erfolg benutzt. Deklarieren Sie eine statische Variable des Fenstertyps. Setzen Sie dann im Konstruktor des Fensters die statische Variable auf "this". Ich habe es in der ganzen App verwendet und es scheint gut zu funktionieren innerhalb von statischen oder Instanzmethoden.
%Vor%Zum Beispiel kann ich das machen.
%Vor%