Un tema recurrente en WPF es como conseguir que solo haya una instancia de tu aplicación, existen varios métodos para ello que vamos a ir viendo.
1.Comprobando si existe el proceso.
Quizá sea la forma mas simple, en la lista de procesos chequeamos si ya existe
1 public partial class App : Application 2 { 3 protected override void OnStartup(StartupEventArgs e) 4 { 5 // Get Reference to the current Process 6 Process thisProc = Process.GetCurrentProcess(); 7 // Check how many total processes have the same name as the current one 8 if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1) 9 { 10 // Si ya existe sacamos un mensaje. 11 MessageBox.Show("La aplicación ya se esta ejecutando."); 12 Application.Current.Shutdown(); 13 return; 14 } 15 16 base.OnStartup(e); 17 } 18 }El único problema que tiene este método es que si a tu aplicación se le pasa argumentos no nos serviría.
2.Usando WindowsFormsApplicationBase
En la librería Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase existe una característica que nos permite controlar si ya se esta ejecutando nuestra aplicación y soluciona el problema anterior. Realmente se utiliza igual que en Windows Forms, eliminamos los ficheros App.xaml y App.cs de manera que quitamos el punto de entrada de nuestra aplicación, añadimos la clase Main con el siguiente código.
1 class Program 2 { 3 [STAThread] 4 public static void Main(string[] args) 5 { 6 WindowsFormsApp wrapper = new WindowsFormsApp(); 7 wrapper.Run(args); 8 } 9 }La clase Wrapper tendría el código:
1 class WindowsFormsApp : WindowsFormsApplicationBase 2 { 3 private App _wpfApp; 4 5 public WindowsFormsApp() 6 { 7 // habilitar una unica instancia 8 IsSingleInstance = true; 9 } 10 11 protected override bool OnStartup(StartupEventArgs e) 12 { 13 14 _wpfApp = new App(); 15 _wpfApp.Run(); 16 17 return false; 18 } 19 20 protected override void OnStartupNextInstance( 21 StartupNextInstanceEventArgs e) 22 { 23 if (e.CommandLine.Count > 0) 24 { 25 _wpfApp.ProcessArguments(e.CommandLine.ToArray()); 26 } 27 } 28 }Por ultimo la clase App
1 class App : Application 2 { 3 protected override void OnStartup(StartupEventArgs e) 4 { 5 base.OnStartup(e); 6 7 MainWindow window = new MainWindow(); 8 window.Show(); 9 } 10 11 public void ProcessArguments(string[] args) 12 { 13 //Procesamos los parametros 14 15 } 16 }Como veis sencillo, aunque a mi no me gusta, ya que metemos características de Winforms, tenemos que añadir librerías y es demasiado código para lo que queremos hacer.
3.Utilizando Mutex
Yo es la que utilizo siempre, es bastante sencilla de implementar y de mantener.
1 private static bool FirstInstance 2 { 3 get 4 { 5 bool created; 6 string name = Assembly.GetEntryAssembly().FullName; 7 8 Mutex mutex = new Mutex(true, name, out created); 9 return created; 10 } 11 }Si recordamos como funciona Mutex, la primera instancia que lo crea pasa a ser propietaria del thread y con la variable created, controlamos si es la instancia que ha creado Mutex, sino es asi nos devolverá un false , de manera que nuestra App.Xaml.cs quedaría
1 protected override void OnStartup(StartupEventArgs e) 2 { 3 if (FirstInstance) 4 base.OnStartup(e); 5 else 6 { 7 MessageBox.Show("Application is already running."); 8 Application.Current.Shutdown(); 9 } 10 }Como veis mas sencillo que en el caso anterior y mucho mas elegante.
Libros de WPF recomendados
Pro Wpf in C# 2008: Windows Presentation Foundation with .Net 3.5
WPF 4 Unleashed
WPF Recipes in C# 2008: A Problem-Solution Approach