2010-02-13 12 views
7

Ho provato un sacco di modi per ottenere un riferimento statico della mia finestra sul mio programma. Ho bisogno di accedere a tutti i suoi membri in fase di runtime da classi diverse, quindi è necessario un riferimento statico.Come ottenere un riferimento statico a una finestra WPF?

Quello che mi piacerebbe avere è qualcosa come Program.Window1, dove Core è statico e MyWindow è uno dei suoi membri statici.

In WinForms, in genere dichiaro il mio modulo statico in Program.cs, ma questo non sembra funzionare con WPF e la loro applicazione personalizzata "App.xaml" ApplicationDefinition.

Come posso farlo?

Nota: ho già provato un certo numero di modi: l'utilizzo di una chiamata diretta a una nuova finestra (ad esempio Program.Window1 = new Window1()) non funzionerà, in quanto ottengo qualche eccezione di invalidità del thread. Come ho capito finora, solo ApplicationDefinitions può avviare Windows in WPF.

Ecco l'eccezione ogni volta che provo a creare una finestra "di codice" e non secondo le impostazioni di StartupUri del XAML ApplicationDefinition:

Il thread chiamante deve essere STA, perché molti componenti dell'interfaccia utente richiedono questo.

+0

È necessario contrassegnare il metodo Main con [STAThread] se è necessario creare finestre nel codice. –

risposta

10

creare una classe statica che può contenere l'oggetto della finestra, e poi, quando viene creata la finestra, hanno esso si passa alla classe statica, da allora in poi la classe statica può distribuire l'oggetto finestra per le parti interessate, anche sebbene l'oggetto finestra stesso non sia statico. Qualcosa come questo. Non è necessario che il tuo modulo sia statico, hai solo bisogno di un posto statico per contenere l'oggetto modulo.

public class Core 
{ 
    internal static MyWindowClass m_Wnd = null; 

    // call this when your non-static form is created 
    // 
    public static void SetWnd(MyWindowClass wnd) 
    { 
     m_Wnd = wnd; 
    } 

    public static MyWindow { get { return m_Wnd; } } 
} 
4

E 'assolutamente possibile istanziare le vostre finestre con WPF. Ma sì, dovresti essere sul "thread UI" (che è un thread STA).

Ad esempio, diciamo che ci piacerebbe avere una proprietà sulla nostra classe App che espone alcune finestre.

public partial class App 
    { 
     private static Window _myWindow; 

     public static Window1 MyWindow 
     { 
      get 
      { 
       if (_myWindow == null) 
        _myWindow = new Window1(); 
       return _myWindow; 
      } 
     } 
    } 

Il problema con questo codice è, come si sono verificati, a seconda di ciò filo sta chiamando il getter MyWindow, new Window1() fallirà se il filo non è uno STA.

Per assicurarsi che la finestra sia stata creata sulla filettatura destra, immettere the Dispatcher object. Questo oggetto viene utilizzato in tutto il WPF per garantire che la comunicazione tra gli elementi dell'interfaccia utente venga eseguita sulla thread corretta.

Torniamo al nostro new Window1, possiamo usare l'oggetto App.Dispatcher per assicurarsi che l'operazione new è fatto sul thread dell'applicazione principale, in questo modo:

 public static Window1 MyWindow 
     { 
      get 
      { 
       if (_myWindow == null) 
       { 
        var window = 
          Application.Current.Dispatcher.Invoke(
           new Func<Window1>(() => new Window1())); 

        _myWindow = (Window1)window; 
       } 

       return _myWindow; 
      } 
     } 

Qui, ottengo una presa della corrente oggetto Dispatcher dell'applicazione e chiama Invoke con un delegato che esegue il nuovo aggiornamento. Invoke assicura che il mio delegato venga eseguito sul thread corretto e restituisce il risultato. Voila, la finestra viene creata senza il temuto errore STA.

Ora, ciò che dovete avere in mente è che ulteriori chiamate fatte sull'istanza MyWindow devono essere fatte anche sul thread corretto. Per evitare di sporcare il tuo codice con le chiamate a Dispatcher.Invoke, potrebbe essere utile racchiudere l'istanza della finestra dietro una semplice API. Per esempio. un metodo Show potrebbe essere implementato in questo modo, avendo cura di maresciallo il Salone chiamata tramite l'oggetto dispatcher della finestra:

 public static void ShowMyWindow() 
     { 
      MyWindow.Dispatcher.Invoke(new Action(MyWindow.Show)); 
     } 
+0

Sembra più appropriato, ma il metodo sopra è più semplice e lo farà. Grazie per la tua risposta però. +1 – Lazlo

+0

Allora va bene :) Grazie per il voto! –

5

provare questo ((MainWindow) App.Current.Windows [0]) MainCanvas..

2

L'ho usato con successo. Dichiarare una variabile statica del tipo di finestra. Quindi nel costruttore della finestra imposta la variabile statica su "this". L'ho usato in tutta l'app e sembra funzionare bene da metodi statici o di istanza.

public static MainWindow screenMain = null; 
    public MainWindow() 
    { 
     InitializeComponent(); 

     screenMain = this; //static reference to this. 

    } 

Per esempio io sono in grado di farlo.

private delegate void del(); 
    .... 
    screenMain.Dispatcher.Invoke(new del(delegate() 
    { 
     screenMain.ButtonSubmit.IsEnabled = true; 
     screenMain.ButtonPreClearing.IsEnabled = true; 
    })); 
Problemi correlati