2009-11-16 62 views
9

如果我將SizeToContent設置爲WidthAndHeight,則WindowStartupLocation="CenterOwner"無法正常工作。而不是新窗口的中心位於其父主的中心,它看起來更像是子窗口的左上角位於父窗口的中心。 如果我刪除SizeToContent那麼一切正常。 有什麼不對?wpf中心子窗口不能與大小寫工作

回答

6

當一個窗口被顯示,則測量它,然後使用由測量過程計算的窗口的ActualWidthActualHeight來處理WindowStartupLocation

您描述的行爲告訴我ActualWidthActualHeight在Show()或ShowDialog()調用時測量爲零或相對較小,並且稍後設置爲非零值。

例如,如果窗口的內容是使用僅在Loaded事件上設置的DataContext構建的,則可能發生這種情況。當調用Show()時,該窗口尚未被Loaded尚未存在,因此它沒有數據。後來當Loaded事件觸發時,它設置DataContext並且窗口更新其內容,但定位已經發生。

還有很多其他場景,例如使用Dispatcher.BeginInvoke調用填充的內容,或者從單獨的線程填充的內容,或者延遲或異步的綁定。

基本上你需要尋找任何可能導致你的窗口內容比目前的Show()被調用時更小的內容,並修復它。

+0

謝謝,我實際上在Show()後加載內容。愚蠢的錯誤,現在工作正常:) – immuner 2009-11-17 11:49:38

1

你的問題有點含糊。你在哪個窗口(「父」或「孩子」)設置SizeToContent和WindowStartupLocation?

如果我在我的項目中創建第二個窗口並按照您描述的方式設置其SizeToContent和WindowStartupLocation,我會得到所需的結果。

我能想到的,你可能會忘記的唯一一件事就是實際上告訴孩子窗口誰是它的主人是:

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

或者,更簡潔:

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

那麼,Ray已經把這一點發揮得淋漓盡致。簡單來說,他想說的是,你要設置你的控件的內容在你Loaded事件,重置Height & Width(以及ActualHeight & ActualWidth)窗口的定位完成之後。

爲了解決這個問題,你有兩個選擇:

  1. 將您的內容值設置代碼構造,或
  2. 添加一個簡單的方法,根據Owner重新計算你的Window的位置,在您的Loaded事件結束時調用此方法,如下所示:

...

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

受約束的動態內容大多是直接呈現Gui,但有時是GUI調度。定時器和其他線程可以啓動(MVVM)屬性更改事件。可以肯定的是,渲染是在接近時間完成的,但沒有保證,因爲要放置WPF Dispacher隊列的優先級。 所以,你不能說什麼時候渲染完成,WPF也不能說處理的順序 - 所以WPF現在不可能成爲計算StartPosition的理想時間。

一個竅門就是等待WPF隊列是空的。那麼你確定WPF有時間處理你的代碼。這意味着,您可以延遲窗口的ShowDialog調用。

因此,爲了執行MVVM的動態內容更改或其他動態更改,需要給GUI-Main線程。 不要試圖手動計算位置,這是非常複雜的,以支持多顯示器。 試試這個代碼打開窗口,它只打開窗口,當WPF完成所有操作

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