如果我将SizeToContent
设置为WidthAndHeight
,则WindowStartupLocation="CenterOwner"
无效。而不是新窗口的中心位于其父所有者的中心,它看起来更像是子窗口的左上角位于父窗口的中心。
如果我删除SizeToContent
,那么一切正常。
有什么问题?
答案 0 :(得分:9)
嗯,雷已经把它放得很好。简单来说,他想说的是,您要在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;
}
}
答案 1 :(得分:6)
当显示窗口时,会对其进行测量,然后使用度量过程计算的窗口的WindowStartupLocation
和ActualWidth
处理ActualHeight
。
您描述的行为告诉我{(1}}和ActualWidth
在Show()或ShowDialog()调用时被测量为零或相对较小,并且稍后才设置为非零值。
例如,如果窗口的内容是使用仅在ActualHeight
事件上设置的DataContext构建的,则会发生这种情况。调用Loaded
时,窗口尚未Show()
,因此它没有数据。稍后当Loaded
事件触发时,它会设置DataContext,窗口会更新其内容,但定位已经发生。
还有许多其他方案,例如使用Dispatcher.BeginInvoke调用填充的内容,或来自单独的线程,或延迟或异步的绑定。
基本上,您需要查找任何可能导致窗口内容在调用Loaded
时小于正常值的内容,并进行修复。
答案 2 :(得分:3)
Binded动态内容主要是直接呈现Gui,但有时会进行GUI调度。计时器和其他线程可以启动(MVVM)属性更改事件。可以肯定的是,渲染是在近时间内完成的,但没有保证,因为定位了WPF Dispacher队列的优先级。 所以,你不能说渲染完成后,WPF无法说出处理顺序 - 所以WPF现在不能是计算StartPosition的理想时间。
一个技巧是,等待,WPF队列是空的。那么你确定,WPF有时间处理你的代码。这意味着,您延迟了Window的ShowDialog调用。
因此,在需要的时候给予GUI-Main Thread ,以便为MVVM或其他动态变化执行动态内容更改。 不要手动计算位置,它非常复杂,支持多显示器。 尝试使用此代码打开窗口,当 WPF完成所有操作时,只打开窗口。
win.Dispatcher.Invoke(new Action(() => win.ShowDialog()), DispatcherPriority.ApplicationIdle);
答案 3 :(得分:1)
你的问题有点含糊不清。在哪个窗口(“父”或“子”)上设置SizeToContent和WindowStartupLocation?
如果我在项目中创建第二个窗口并按照您描述的方式设置其SizeToContent和WindowStartupLocation,我会得到所需的结果。
我唯一可以想到的是你可能会忘记的是实际告诉孩子窗口其所有者是谁:
Window2 w = new Window2();
w.Owner = this; // "this" being the parent window
w.ShowDialog();
或者,更简洁:
new Window2 { Owner = this }.ShowDialog();