2009-11-16 12 views
9

Se si imposta SizeToContent su WidthAndHeight, quindi WindowStartupLocation="CenterOwner" non funziona correttamente. Invece che il centro della nuova finestra si trova al centro del suo proprietario genitore, sembra più che l'angolo in alto a sinistra della finestra figlio sia al centro del genitore. Se rimuovo SizeToContent allora tutto va bene. Cosa c'è che non va?finestra figlio wpf center non funzionante con sizetocontent

risposta

6

Quando una finestra viene mostrato, viene misurato, quindi WindowStartupLocation viene elaborato utilizzando ActualWidth e ActualHeight della finestra calcolata dal processo di misura.

Il comportamento descritto mi dice che ActualWidth e ActualHeight sono misurati come zero o relativamente piccoli al momento della chiamata Show() o ShowDialog() e solo successivamente impostati su valori diversi da zero.

Ciò può accadere se, ad esempio, il contenuto della finestra viene creato utilizzando un DataContext impostato solo su un evento Loaded. Quando si chiama Show(), la finestra non è stata ancora Loaded quindi non ha dati. Successivamente, quando viene attivato l'evento Loaded, imposta DataContext e la finestra ne aggiorna il contenuto, ma il posizionamento è già presente.

Esistono molti altri scenari, ad esempio contenuti riempiti utilizzando una chiamata Dispatcher.BeginInvoke o da un thread separato o binding ritardati o asincroni.

Fondamentalmente è necessario cercare tutto ciò che potrebbe causare il contenuto della finestra per essere più piccolo del normale al momento si chiama Show() e correggerlo.

+0

Grazie, stavo effettivamente caricando il contenuto subito dopo Show(). Errore stupido, funziona bene ora :) – immuner

1

La tua domanda è un po 'ambigua. Su quale finestra ("genitore" o "figlio") stai impostando SizeToContent e WindowStartupLocation?

Se creo una seconda finestra nel mio progetto e ne imposto SizeToContent e WindowStartupLocation nel modo in cui descrivi, ottengo i risultati desiderati.

L'unica cosa che posso pensare che si può essere dimenticando è quello di raccontare in realtà la finestra bambino che il suo proprietario è:

Window2 w = new Window2(); 
w.Owner = this; // "this" being the parent window 
w.ShowDialog(); 

Oppure, più succintamente:

new Window2 { Owner = this }.ShowDialog(); 
9

Beh, Ray ha messo brillantemente questo. In termini semplici, quello che vuole dire è che si sta impostando il contenuto dei controlli nel vostro Loaded evento, che resetta il Height & Width (e anche il ActualHeight & ActualWidth) dopo il posizionamento della finestra è fatto.

Per risolvere questo problema, si hanno due alternative:

  1. spostare il vostro codice di impostazione del valore dei contenuti al costruttore, o,
  2. Aggiungere un metodo semplice per ricalcolare la posizione del Window secondo il Owner e chiama questo metodo alla fine del tuo evento Loaded, in questo modo:

...

private void CenterOwner() 
{ 
    if (Owner != null) 
    { 
     double top = Owner.Top + ((Owner.Height - this.ActualHeight)/2); 
     double left = Owner.Left + ((Owner.Width - this.ActualWidth)/2); 

     this.Top = top < 0 ? 0 : top; 
     this.Left = left < 0 ? 0 : left; 
    } 
} 
2

Il contenuto dinamico associato è in gran parte reso Gui-direttamente ma a volte inviato tramite GUI. Timer e altri thread possono avviare eventi di modifica delle proprietà (MVVM). È certo, che il rendering viene eseguito in un tempo prossimo, ma non garantito, poiché posiziona una priorità della coda Dispatch di WPF. Quindi, non è possibile dire quando il rendering è finito, e WPF non può dire qualcosa sull'ordine di elaborazione, quindi WPF non può ora il momento ideale per calcolare la StartPosition.

Un trucco è, attendere, che la coda WPF sia emtpy. Allora sei sicuro che, WPF ha il tempo di elaborare il tuo codice. Ciò significa che si ritarda la chiamata ShowDialog per la finestra.

Quindi fornire il thread principale della GUI tutto il tempo necessario per, per eseguire le modifiche del contenuto dinamico per MVVM o altre modifiche dinamiche. Non provare a calcolare la posizione manualmente, è molto complesso, per supportare display multipli. Prova questo codice per aprire la finestra, apre solo la finestra, quando WPF ha completato tutte le operazioni.

 win.Dispatcher.Invoke(new Action(() => win.ShowDialog()), DispatcherPriority.ApplicationIdle); 
Problemi correlati