2010-05-28 3 views
6

Prima un po 'di background: ho un'applicazione WPF, che è una GUI front-end per un'applicazione legacy Win32. L'app legacy viene eseguita come DLL in un thread separato. I comandi che l'utente sceglie nell'interfaccia utente vengono richiamati su quel "thread legacy".Application.Current.Shutdown() vs. Application.Current.Dispatcher.BeginInvokeShutdown()

Se il "thread legacy" termina, la GUI-front-end non può più fare nulla di utile, quindi ho bisogno di chiudere l'applicazione WPF. Pertanto, alla fine del metodo del thread, chiamo Application.Current.Shutdown().

Poiché non sono sul thread principale, devo richiamare questo comando. Tuttavia, ho notato che il Dispatcher ha anche BeginInvokeShutdown() per arrestare il dispatcher. Quindi la mia domanda è: Qual è la differenza tra invocando

Application.Current.Shutdown(); 

e chiamando

Application.Current.Dispatcher.BeginInvokeShutdown(); 

risposta

7

ho fatto un po 'di prove, e ora credo di sapere le differenze:

1) Come indicato nella pagina di MSDN, BeginInvokeShutdown, oltre spegnere il Dispatcher, è anche possibile cancellare/interrompe la sua coda. Shutdown innanzitutto gestisce tutti gli elementi nella coda del Dispatcher.

Una volta avviato il processo di spegnimento, tutti gli elementi di lavoro in sospeso nella coda vengono interrotti.

2) In un'applicazione sono in grado di gestire l'evento Application.Exit. Questo evento viene generato quando chiamo Shutdown, ma NON viene attivato quando chiamo BeginInvokeShutdown! Lo stesso vale per Window.Closing e Window.Closed.

Per quanto riguarda le somiglianze, in entrambi i casi viene interrotta la filettatura principale. A seconda degli altri thread in esecuzione, questo arresta anche il processo: i thread non in background vengono eseguiti fino al completamento prima che il processo venga chiuso.

Di seguito è riportato il mio codice di test. Commento uno o l'altro metodo di chiamata in Application_Startup:

public partial class App 
{ 
    private void Application_Exit(object sender, ExitEventArgs e) 
    { 
     MessageBox.Show("Exiting"); 
    } 

    private void Application_Startup(object sender, StartupEventArgs e) 
    { 
     var testThread = new Thread(
      () => 
      { 
       Thread.Sleep(2000); 
       Application.Current.Dispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Send); 
       //Application.Current.Dispatcher.BeginInvoke(new Action(() => Application.Current.Shutdown())); 
      }); 
     testThread.Start(); 
    } 
} 

public partial class Window1 
{ 
    public Window1() 
    { 
     this.InitializeComponent(); 

     Dispatcher.BeginInvoke(new Action(() => 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("One"); 
     })); 

     Dispatcher.BeginInvoke(new Action(() => 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("Two"); 
     })); 

     Dispatcher.BeginInvoke(new Action(() => 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("Three"); 
     })); 

     Dispatcher.BeginInvoke(new Action(() => 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("Four"); 
     })); 
    } 

    private void Window_Closed(object sender, EventArgs e) 
    { 
     Console.WriteLine("Closed"); 
    } 

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
    { 
     Console.WriteLine("Closing"); 
    } 
} 
1

MSDN page for Shutdown()
MSDN page for BeginInvokeShutdown()

Sembra che questo è solo uno scontro di terminologia. BeginInvokeShutdown chiude il dispatcher , la tua applicazione in teoria può continuare a vivere in seguito (sebbene senza un dispatcher, sarebbe piuttosto limitata). Shutdown tuttavia in realtà esce dall'applicazione, che è ciò che desideri.

+0

Bene, questa è esattamente la domanda alla quale non viene data risposta nella documentazione: La chiusura del dispatcher dell'applicazione spegne anche l'applicazione? –

+0

Per questo ho creato una semplice applicazione di test WPF. Per simulare il tuo codice, ho fatto: 'Thread t = new Thread (new ThreadStart (delegate() {Thread.Sleep (50000);})); t.Start(); Application.Current.Dispatcher .BeginInvokeShutdown (System.Windows.Threading.DispatcherPriority.Normal); '. L'arresto del Dispatcher ha ucciso il suo thread proprietario e ha chiuso la finestra, ma * non * ha ucciso il thread in background. – JustABill

+0

Due piccole differenze: 1) chiamo shutdown nel secondo thread (anche se attraverso i test posso vedere che non fa differenza). 2) Ho il secondo thread impostato come thread in background (IsBackground = true). In questo modo, viene anche ucciso se il thread principale si chiude. –

0

A proposito, Daniel - la nostra applicazione è costruita nello stesso modo - WPF front-end per un'applicazione di Win32 COM (Delphi) in esecuzione separatamente. Sarebbe interessante parlare e confrontare i nostri approcci.

Ma perché mi sono imbattuto nella tua domanda è che la nostra applicazione usava chiamare Dispatcher.BeginInvokeShutdown, che funzionava bene con l'eccezione di alcuni casi in cui non si concludeva correttamente. Quando finalmente ho messo le mani su una macchina su cui questo era riproducibile, passare a Application.Current.Shutdown() ha risolto il problema. Ancora non capisco quale fosse il problema.

+0

Suppongo che sia perché la chiamata a Dispatcher.BeginInvokeShutdown() interrompe/cancella tutti i messaggi in sospeso. Nel mio caso, eseguo anche un po 'di pulizia nei casi Window.Closing/Closed e Application.Exit (per arrestare la parte Win32). –