【发布时间】:2010-12-16 21:43:27
【问题描述】:
如果我将SizeToContent 设置为WidthAndHeight,则WindowStartupLocation="CenterOwner" 无法正常工作。而不是新窗口的中心位于其父窗口的中心,它看起来更像是子窗口的左上角位于父窗口的中心。
如果我删除 SizeToContent 则一切正常。
怎么了?
【问题讨论】:
标签: wpf sizetocontent
如果我将SizeToContent 设置为WidthAndHeight,则WindowStartupLocation="CenterOwner" 无法正常工作。而不是新窗口的中心位于其父窗口的中心,它看起来更像是子窗口的左上角位于父窗口的中心。
如果我删除 SizeToContent 则一切正常。
怎么了?
【问题讨论】:
标签: wpf sizetocontent
嗯,雷把这件事做得很出色。简单来说,他想说的是,您在Loaded 事件中设置控件的内容,这会在之后重置Height 和Width(以及ActualHeight 和ActualWidth)窗口的定位就完成了。
要解决此问题,您有两种选择:
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;
}
}
【讨论】:
当一个窗口被显示时,它被测量,然后WindowStartupLocation 使用测量过程计算的窗口的ActualWidth 和ActualHeight 进行处理。
您描述的行为告诉我 ActualWidth 和 ActualHeight 在 Show() 或 ShowDialog() 调用时测量为零或相对较小,并且稍后才设置为非零值。
例如,如果窗口的内容是使用仅在 Loaded 事件上设置的 DataContext 构建的,则可能会发生这种情况。当调用Show() 时,窗口还不是Loaded,所以它没有数据。稍后当Loaded 事件触发时,它会设置 DataContext 并且窗口会更新其内容,但定位已经发生。
还有许多其他场景,例如使用 Dispatcher.BeginInvoke 调用填充的内容,或来自单独的线程,或延迟或异步的绑定。
基本上,在调用Show() 时,您需要查找可能导致窗口内容小于正常值的任何内容,然后修复它。
【讨论】:
绑定的动态内容大多直接通过 GUI 呈现,但有时通过 GUI 调度。计时器和其他线程可以启动 (MVVM) 属性更改事件。可以肯定的是,渲染是在很短的时间内完成的,但不是保证的,因为定位 WPF 调度程序队列的优先级。 所以,你不能说渲染什么时候完成,WPF也不能说处理的顺序——所以WPF现在不能计算StartPosition的理想时间。
一个技巧是,等待,WPF 队列是空的。那么你确定,WPF 有时间处理你的代码。这意味着,您延迟了 Window 的 ShowDialog 调用。
所以给 GUI 主线程它需要的所有时间,以执行 MVVM 的动态内容更改或其他动态更改。 不要尝试手动计算位置,非常复杂,支持多显示。 试试这个代码打开窗口,它只打开窗口,当WPF完成所有操作。
win.Dispatcher.Invoke(new Action(() => win.ShowDialog()), DispatcherPriority.ApplicationIdle);
【讨论】:
你的问题有点模棱两可。您在哪个窗口(“父”或“子”)上设置 SizeToContent 和 WindowStartupLocation?
如果我在我的项目中创建第二个窗口并按照您描述的方式设置它的 SizeToContent 和 WindowStartupLocation,我会得到想要的结果。
我能想到的你可能忘记的唯一一件事就是告诉子窗口它的所有者是谁:
Window2 w = new Window2();
w.Owner = this; // "this" being the parent window
w.ShowDialog();
或者,更简洁:
new Window2 { Owner = this }.ShowDialog();
【讨论】: