我需要在另一个表格之前显示一个表格,这导致我提出以下问题。
为什么一个表单可以有一个起始位置,CenterParent而字段this.Parent等于 null?
它必须知道父节点才能正确定位自己,但它Parent没有设置该字段。这很奇怪。我错过了什么吗?
Form2 f = new Form2();
f.ShowDialog();
这就是我在子表单上所做的一切。父级设置为默认窗口位置。无论我将父窗体移动到何处,子窗体都会显示在父窗体的中心。
有关所有者的信息通过 API 调用传递给创建的对话框(您可以在 ShowDialog(IWin32Window owner) 方法中的 Reflector 中看到):
UnsafeNativeMethods.SetWindowLong(new HandleRef(this, base.Handle), -8, new HandleRef(owner, handle));
如果在 ShowDialog 调用中没有指定所有者,owner则通过 GetActiveWindow API 调用计算变量:
IntPtr activeWindow = UnsafeNativeMethods.GetActiveWindow();
IntPtr handle = (owner == null) ? activeWindow : Control.GetSafeHandle(owner);
要访问 Owner f 对话框表单,您可以使用GetWindowLong API 调用:
IntPtr ownerHandle = NativeMethods.GetWindowLong(nonModalForm.Handle, -8);
在 Winforms 中,窗口的父级和所有者之间的区别有点混乱。在这种情况下,CenterParent 真正的意思是 CenterOwner。不是 Windows 功能,它是在 Winforms 中实现的,由基本的 Form.OnLoad() 方法完成。一个对话框应该总是有一个所有者,当你没有在 ShowDialog() 调用中指定一个时,它会寻找一个所有者。其中使用 GetActiveWindow() 作为最佳猜测。
要亲自查看,请在对话框表单中重载 OnLoad,如下所示:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
this.StartPosition = FormStartPosition.CenterParent;
}
protected override void OnLoad(EventArgs e) {
//base.OnLoad(e);
}
}
请注意,它不再以所有者为中心。
可以在Reference Source,Form.cs类,OnLoad方法中看到相关代码:
if (GetState(STATE_MODAL)) {
FormStartPosition startPos = (FormStartPosition)formState[FormStateStartPos];
if (startPos == FormStartPosition.CenterParent) {
CenterToParent();
}
else if (startPos == FormStartPosition.CenterScreen) {
CenterToScreen();
}
}
我相信出于某种原因,此信息由 .NET Framework 内部存储。无论如何,如果您想访问父表单,可以将其设置为子表单的Owner 属性:
Form form = new Form();
form.Owner = this;
form.Show();
然后在子窗体中,您可以使用 Owner 属性访问父窗体。当一个表单被另一个表单拥有时,它会被最小化并与所有者表单一起关闭。拥有的表格也永远不会显示在其拥有者表格的后面,如果我理解正确的话,这正是您所需要的。
此代码将打开父 TAG 中间的对话框。
ObjectDistrubution od = new ObjectDistrubution();
od.StartPosition = FormStartPosition.CenterParent;
od.ShowDialog();