2009-11-16 57 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);