2010-02-13 25 views
7

He intentado una gran cantidad de formas de obtener una referencia estática de mi ventana en mi programa. Necesito acceder a todos sus miembros en tiempo de ejecución desde diferentes clases, por lo que se necesita una referencia estática.¿Cómo obtener una referencia estática a una ventana de WPF?

Lo que me gustaría tener es algo así como Program.Window1, donde Core es estático y MyWindow es uno de sus miembros estáticos.

En WinForms, generalmente declaro mi forma estática en Program.cs, pero esto no parece funcionar con WPF y su ApplicationDefinition "App.xaml" personalizada.

¿Cómo puedo hacerlo?

Nota: Ya lo he intentado de varias maneras: el uso de una llamada directa a una nueva ventana (es decir, Program.Window1 = new Window1()) no funcionará, ya que obtengo una excepción de invalidez de subprocesos. Como entiendo hasta ahora, solo ApplicationDefinitions puede iniciar Windows en WPF.

Aquí es la excepción siempre que intente crear una ventana "por el código" y no por el valor por defecto de StartupUri XAML ApplicationDefinition:

El subproceso de llamada debe ser STA, debido a que muchos componentes de interfaz de usuario requieren.

+0

Tiene que marcar el método Principal con [STAThread] si necesita crear ventanas en el código. –

Respuesta

10

Cree una clase estática que pueda contener el objeto ventana, y luego cuando se crea la ventana, hágalo pasar a la clase estática, desde allí la clase estática puede entregar el objeto ventana a las partes interesadas incluso aunque el objeto ventana no es estático Algo como esto. No es necesario que su formulario sea estático, solo necesita un lugar estático para contener el objeto de formulario.

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

Es absolutamente posible crear su propia ventana con WPF. Pero sí, tendrías que estar en el "hilo UI" (que es un hilo STA).

Por ejemplo, supongamos que nos gustaría tener una propiedad en nuestra clase de aplicación que exhiba algunas ventanas.

public partial class App 
    { 
     private static Window _myWindow; 

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

El problema con este código es, como usted ha experimentado, dependiendo de lo que el hilo está llamando el captador MyWindow, new Window1() fallará si el hilo no es un STA.

Para asegurarse de que la ventana se crea en el hilo derecho, ingrese the Dispatcher object. Este objeto se usa a través de WPF para garantizar que la comunicación entre los elementos de la interfaz de usuario se realice en el hilo correcto.

Volver a nuestra new Window1, podemos utilizar el objeto App.Dispatcher para asegurarse de que la operación se realiza new en el hilo principal de la aplicación, así:

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

        _myWindow = (Window1)window; 
       } 

       return _myWindow; 
      } 
     } 

Aquí, consigo un alto en la corriente el objeto Dispatcher de la aplicación y llama al Invoke con un delegado que realiza la actualización real. Invoke asegura que mi delegado se ejecuta en el hilo correcto y devuelve el resultado. Voila, la ventana se crea sin el temido error STA.

Ahora, lo que debe tener en cuenta es que las otras llamadas realizadas en la instancia de MyWindow también se deben realizar en la secuencia correcta. Para evitar ensuciar su código con llamadas a Dispatcher.Invocar, podría ser útil ajustar la instancia de ventana detrás de una API simple. P.ej. Mostrar un método podría ser implementado como este, asegurándose de reunir el Salón llamada a través del objeto despachador de la ventana:

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

Parece más apropiado, pero el método anterior es más simple y lo hará. Gracias por tu respuesta. +1 – Lazlo

+0

Entonces está bien :) ¡Gracias por votar! –

5

probar este ((MainWindow) App.Current.Windows [0]) MainCanvas..

2

Lo he usado con éxito. Declara una variable estática del tipo de ventana. Luego, en el constructor de la ventana, establezca la variable estática en "this". Lo he usado en toda la aplicación y parece funcionar bien desde métodos estáticos o de instancia.

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

     screenMain = this; //static reference to this. 

    } 

Por ejemplo, yo soy capaz de hacer esto.

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