2010-09-30 33 views
5

Quiero hacer de MainWindow un singleton porque quiero facilitar el acceso desde todas las demás ventanas de mi aplicación. Pero no pude hacerlo correr. Aquí esta lo que hice.¿Cómo hacer que mi WPF MainWindow sea singleton?

Como de costumbre, hice que el contratista de MainWindow sea privado y creé una propiedad public static MainWindow Instance para devolver una instancia estática. Cuando solo lo ejecuto sin ningún otro cambio, obtuve el error "No hay fuente disponible". Busqué en Internet y encontré un tema relacionado en http://www.netframeworkdev.com/windows-presentation-foundation-wpf/xamlc-singleton-class-80578.shtml. Sin embargo, no pude hacer que funcione como se sugiere allí. Algunos sugieren que hacer un cambio en MainWindow.xaml de

<Window x:Class="TestApp.MainWindow" 

a

<Window x:Class="TestApp.MainWindow.Instance" 

que parece lógico. Sin embargo, cuando hice esto, obtuve un montón de errores de compilación (el primero dice que el espacio de nombres TestApp ya contiene una definición de 'MainWindow').

Encontré muchos artículos en Internet sobre cómo hacer aplicaciones de instancia única. No estoy buscando esto. Solo quiero hacer de MainWindow un singleton. Lo he hecho en aplicaciones WinForm muchas veces.

Respuesta

11

Para hacer el MainWindow un conjunto unitario, estos son los pasos que debe realizar: Añadir una clase MainWindowInstance a MainWindow ...

public static MainWindow Instance { get; private set; } 

Nota: Conjunto de acceso es privado para que nadie más puede establecer a cualquier otra cosa.

Añadir un constructor estático en MainWindow y crea el constructor de MainWindowprivate, así ...

static MainWindow() 
{ 
    Instance = new MainWindow(); 
} 

private MainWindow() 
{ 
    InitializeComponent(); 
} 

Ahora quite StartupUri="MainWindow.xaml" de su archivo App.xaml de manera que no hay ninguna ventana predeterminado se inicia cuando se inicia la aplicación. Capturar el evento de inicio de la clase App en App.xaml.cs así:

public App() 
{ 
    ... 
    Startup += App_Startup; 
    ... 
} 

void App_Startup(object sender, StartupEventArgs e) 
{ 
    TestApp.MainWindow.Instance.Show(); 
} 
+0

Tienes que hacer esto en un constructor estático o perezosamente en el getter 'Instance'. Además, para singleton generalmente haces que los constructores sean privados. En su ejemplo, los consumidores pueden crear múltiples instancias MainWindow y la última será asignada a 'Instance' –

+0

Al menos si desea implementar correctamente el patrón singleton. Este código obviamente funcionará en el sentido de que otras clases pueden acceder a la ventana principal desde la propiedad 'Instance', pero no es singleton" puro "IMHO –

+0

Sí, estoy de acuerdo. Ver el código modificado. – Yogesh

12

No estoy seguro de hacerlo único, pero ¿por qué lo haría? Puede usar Application.Current.MainWindow para obtener la propiedad Application.MainWindow en cualquier momento desde cualquier lugar de su aplicación. Consulte: http://msdn.microsoft.com/en-us/library/system.windows.application.mainwindow(v=VS.90).aspx.

Window mainWin = Application.Current.MainWindow; 
mainWin.Title = "This will be set as the title of the Main Window"; 

Por lo que es Singleton todavía no tiene sentido para mí - ¿Cómo le hace más accesible? Siempre se puede guardar relación con su ventana principal en una variable estática pública - esto se podría establecer en el constructor de la ventana principal:

public partial class MainWindow : Window 
{ 
    public static MainWindow myMainWindow; // ASSUMPTION: only one MainWindow is ever constructed otherwise this will be overwritten by latest such instance 

    public MainWindow() 
    { 
     InitializeComponent();    
     myMainWindow = this; 
    } 
} 

Pero dada la Application.Current.MainWindow anterior ¿por qué preocuparse ..

+0

¿Qué hay de otra parte del código doint este Winow1 = new Window1(), se creará otra instancia. – TalentTuner

+0

Mnl. Sí, sé que puedo hacer eso, pero solo quiero hacer mi vida un poco más fácil. Por lo tanto, quiero llamar MainWindow.Instance.DoSomething() en lugar de ((MainWindow) Application.Current.MainWindow) .DoSomething(). – newman

+0

Entendido, en ese caso guardar una referencia estática como la anterior debería hacer su vida más fácil. – markmnl

4

Elimina StartupUri="MainWindow.xaml" de tu archivo App.xaml. WPF ya no abrirá ninguna ventana para ti.

<Application x:Class="WpfApplication1.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
</Application> 

agregar un controlador a la Startup evento de su clase en AppApp.xaml.cs.
En este controlador, llame al método Show() de su instancia singleton.

using System; 
using System.Windows; 

namespace WpfApplication1 
{ 
    public partial class App : Application 
    { 
     public App() 
     { 
      Startup += new StartupEventHandler(App_Startup); 
     } 

     void App_Startup(object sender, StartupEventArgs e) 
     { 
      WpfApplication1.MainWindow.Instance.Show(); 
     } 
    } 
} 

Nota:App La clase tiene una propiedad llamada MainWindow, por tanto, en App_Startup() que prefija la clase MainWindow con el espacio de nombres!

0

Gracias todos por los answsers rápidas. El punto clave es que tengo que eliminar StartupUri="MainWindow.xaml" de App.xaml. Gracias también por la punta del contructor estático. Otro punto que quiero mencionar es que también podemos anular OnStartup para que se inicie la ventana principal (sólo para unas pocas líneas más cortas):

public partial class App : Application 
    { 
     protected override void OnStartup(StartupEventArgs e) 
     { 
      base.OnStartup(e); 
      TestApp.MainWindow.Instance.Show(); 
     } 
    } 
Cuestiones relacionadas