2015-10-10 16 views
5

Mi sono imbattuto in un caso strano in cui l'evento Close si propagava alla finestra padre e ne determina la chiusura.Perché si propagherà l'evento Window.Close?

Ho fatto un esempio minimo, come illustrato di seguito

Per TestWindow non è altro che la finestra WPF predefinito generato da VS

in App.xaml.cs sovrascrivo caso OnStartup e uso come Main funzione personalizzata

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 

    TestWindow t = new TestWindow(); 
    t.ShowDialog(); 
} 

Ora, se si fa clic sul pulsante X per chiudere TestWindow, l'applicazione si arresta invece di mostrare MainWindow. Se si commenta t.ShowDialog, lo MainWindow verrà visualizzato correttamente. Avanti se si ascolta la Closing caso di MainWindow troverete che si attiverà dopo il TestWindow chiude, che non mi sembra giusto

risposta

4

In realtà non è moltiplicazione, WPF gestisce la prima finestra di dialogo e su comunicazioni di chiusura che il processo non ha più finestre presenti. WPF pubblica un'applicazione chiude il messaggio per l'elaborazione successiva. Nel frattempo il tuo codice ha continuato a visualizzare un'ulteriore finestra che durante l'elaborazione del messaggio pompa incontra il messaggio di uscita e chiude così la finestra e termina la tua app.

registro

Debug:

Informazioni: 0: App OnStartup

Informazioni: 0: nuovo MainWindow

Informazioni: 0: MainWindow chiusura

Informazioni: 0: App uscendo

Per risolvere, è necessario rimuovere StartupUri e gestire invece l'evento Startup.

Cambio:

<Application x:Class="WpfCloseProblem.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfCloseProblem" 
     StartupUri="MainWindow.xaml"> ... 

... a:

<Application x:Class="WpfCloseProblem.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:WpfCloseProblem" 
      Startup="Application_Startup"> 

poi scarta il codice a OnStartup e invece definire un gestore per avvio:

//protected override void OnStartup(StartupEventArgs e) 
//{ 
// base.OnStartup(e); 
// 
// TestWindow t = new TestWindow(); 
// t.ShowDialog(); 
//} 

private void Application_Startup(object sender, StartupEventArgs e) 
{ 
    var main = new MainWindow(); 

    TestWindow t = new TestWindow(); 
    t.ShowDialog(); 

    main.Show(); 
} 

In precedenza sono stato in grado per confermare che dopo la chiusura della finestra di dialogo è stato creato MainWindow; caricato e chiuso in rapida successione.

+0

Possiamo solo aggiungere il codice per 'OnStartup ', non è necessario un gestore separato. Mi piace questo approccio. Comunque sarebbe perfetto se spiegassi l'App scegliendo la sua MainWindow (come faccio nella mia risposta). Con quella aggiunta, questa è la risposta più perfetta e concordo sul fatto che ciò che ho suggerito sull'impostazione esplicita della MainWindow non è buono come questo (a meno che non venga usato 'ShowDialog()'). –

+1

Grazie a @KingKing. Sì, sono un po 'in perdita per la spiegazione, purtroppo. Ho pensato che potesse essere qualcosa a che fare con la prima finestra mostrata come _dialog_ e forse quando è chiusa, WPF dice _ "oh non ci sono più finestre, tempo di uscire" _. Ho pensato a Windows normale in cui le finestre di dialogo hanno la loro pompa di messaggi. Non sono sicuro se è correlato. Anche se questo è WPF, non sono sicuro di quanto siano simili. Continuerò a indagare. Buon fine settimana! – MickyD

+0

@KingKing possibile spiegazione aggiunta – MickyD

3

Il modo in cui App funziona qui è che sceglie la prima finestra avviata come finestra principale. Quindi nel tuo caso, il TestWindow verrà scelto come finestra principale. Lo ShutdownMode nel codice è in qualche modo impostato su OnMainWindowClose. Quindi, dopo aver chiuso TestWindow, tutte le finestre secondarie (incluso il tuo MainWindow) hanno il loro Closing attivato.

Così il problema qui non si propaga, ma moltiplicazione giù l'evento di chiusura.

Non si dovrebbe creare alcuna finestra prima che la finestra principale venga effettivamente avviata per prima. Oppure, se lo desideri, puoi impostare ShutdownMode a OnLastWindowClose.

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 
    Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose; 
    TestWindow t = new TestWindow(); 
    t.ShowDialog(); 
} 

Oppure si può impostare il MainWindow esplicitamente nel costruttore della finestra principale:

public MainWindow(){ 
    InitializeComponent(); 
    Application.Current.MainWindow = this; 
} 

Tuttavia se si utilizza ShowDialog(), non c'è modo per voi di impostare la MainWindow esplicitamente. Perché subito dopo aver chiuso lo TestWindow (in quel momento è ancora la finestra principale), l'intera app verrà chiusa.

Edit: non trovo alcun riferimento di questo, ma esso può essere controllato e possiamo essere sicuri di questo, qui è la messa a punto:

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 
    new TestWindow();//not even need to be shown 
    var wm = Application.Current.MainWindow;// points to the new TestWindow 
    //If there is not any Window init here, the MainWindow is just null  
} 
+0

Per la prima finestra avviata intendi prima inizializzato uno o il primo per mostrare? – Steve

+0

@Inserire il primo inizializzato. Ho provato a debuggarlo e il costruttore di 'MainWindow' viene chiamato dopo' OnStartup() 'che significa che viene chiamato dopo' TestWindow() '. –

+0

ti capita di avere il sorgente per la prima finestra avviata = parte della finestra principale? Mi piacerebbe leggere di più su di esso – Steve

Problemi correlati