如果我设置SizeToContent
为WidthAndHeight
,则WindowStartupLocation="CenterOwner"
无法正常工作。而不是新窗口的中心位于其父所有者的中心,它看起来更像是子窗口的左上角位于父窗口的中心。如果我删除SizeToContent
,那么一切都好。怎么了?
4 回答
好吧,雷把这件事做得很出色。简单来说,他想说的是,您正在事件中设置控件的内容,这会在窗口定位完成后Loaded
重置Height
& Width
(以及ActualHeight
& )。ActualWidth
要解决此问题,您有两种选择:
- 将您的内容值设置代码移动到构造函数,或者,
- 添加一个简单的方法来
Window
根据重新计算您的位置,Owner
并在事件结束时调用此方法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() 调用时被测量为零或相对较小,并且稍后才设置为非零值。
例如,如果窗口的内容是使用仅在事件上设置的 DataContext 构建的,则可能会发生这种情况Loaded
。当Show()
被调用时,窗口还没有出现Loaded
,所以它没有数据。稍后当Loaded
事件触发时,它会设置 DataContext 并且窗口会更新其内容,但定位已经发生。
还有许多其他场景,例如使用 Dispatcher.BeginInvoke 调用填充的内容,或者来自单独的线程,或者延迟或异步的绑定。
基本上,您需要寻找任何可能导致您的窗口内容小于当前Show()
调用的内容,并修复它。
绑定的动态内容主要是直接通过 GUI 呈现,但有时通过 GUI 调度。计时器和其他线程可以启动 (MVVM) 属性更改事件。可以肯定的是,渲染是在很短的时间内完成的,但不是保证的,因为定位 WPF 调度程序队列的优先级。所以,你不能说渲染什么时候完成,WPF 也不能说处理的顺序——所以 WPF 现在不能计算 StartPosition 的理想时间。
一个技巧是,等待,WPF 队列是空的。那么你确定,WPF 有时间处理你的代码。这意味着,您延迟了 Window 的 ShowDialog 调用。
所以给 GUI-Main 线程它需要的所有时间,以执行 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();