FormStartPosition.CenterParent不起作用

问题描述 投票:30回答:12

在下面的代码中,只有第二种方法适用于我(.NET 4.0)。 FormStartPosition.CenterParent不会将子表格置于其父级之上。为什么?

资料来源:this SO question

using System;
using System.Drawing;
using System.Windows.Forms;

class Program
{
  private static Form f1;

  public static void Main()
  {
    f1 = new Form() { Width = 640, Height = 480 };
    f1.MouseClick += f1_MouseClick; 
    Application.Run(f1);
  }

  static void f1_MouseClick(object sender, MouseEventArgs e)
  {
    Form f2 = new Form() { Width = 400, Height = 300 };
    switch (e.Button)
    {
      case MouseButtons.Left:
      {
        // 1st method
        f2.StartPosition = FormStartPosition.CenterParent;
        break;
      }
      case MouseButtons.Right:
      {
        // 2nd method
        f2.StartPosition = FormStartPosition.Manual;
        f2.Location = new Point(
          f1.Location.X + (f1.Width - f2.Width) / 2, 
          f1.Location.Y + (f1.Height - f2.Height) / 2
        );
        break;
      }
    }
    f2.Show(f1); 
  }
}
c# winforms forms parent-child centering
12个回答
33
投票

这是因为你没有告诉f2它的Parent是谁。

如果这是一个MDI应用程序,那么f2应该将其MdiParent设置为f1

Form f2 = new Form() { Width = 400, Height = 300 };
f2.StartPosition = FormStartPosition.CenterParent;
f2.MdiParent = f1;
f2.Show();

如果这不是MDI应用程序,那么您需要使用ShowDialog作为参数调用f1方法。

Form f2 = new Form() { Width = 400, Height = 300 };
f2.StartPosition = FormStartPosition.CenterParent;
f2.ShowDialog(f1);

请注意,CenterParentShow无法正常工作,因为无法设置Parent,因此如果ShowDialog不合适,则手动方法是唯一可行的方法。


1
投票

也许这可以帮助别人。

Form frmMessage = new Form();

从经验来看,虽然它们看起来相似,但它们表现不同:

此变体不起作用:

if (frmMessage.Parent != null)
    frmMessage.CenterToParent();
else
    frmMessage.CenterToScreen();

这种变体有效

if (frmMessage.Parent != null)
    frmMessage.StartPosition = FormStartPosition.CenterParent;
else
    frmMessage.StartPosition = FormStartPosition.CenterScreen;

0
投票

对JYelton的回答微不足道

Form2_Load(object sender, EventArgs e)
{
    if (Owner != null && Parent == null && StartPosition == FormStartPosition.CenterParent)
    Location = new Point(Owner.Location.X + Owner.Width / 2 - Width / 2,
        Owner.Location.Y + Owner.Height / 2 - Height / 2);
}

0
投票

我知道一个老问题,但我有同样的问题,但出于不同的原因。

我打开的表单有一个重写的OnLoad方法:

protected override void OnLoad(EventArgs e)
{
   //... etc.
}

但是没有调用基础实现as it must do

protected override void OnLoad(EventArgs e)
{
   //... etc.
   base.OnLoad(e);
}

在派生类中重写OnLoad(EventArgs)时,请确保调用基类的OnLoad(EventArgs)方法,以便已注册的委托接收事件。


33
投票

如果您设置子表单的所有者,如下所示:

Form2 f = new Form2();
f.Show(this);

然后你可以像这样轻松地居中:

Form2_Load(object sender, EventArgs e)
{
    if (Owner != null)
        Location = new Point(Owner.Location.X + Owner.Width / 2 - Width / 2,
            Owner.Location.Y + Owner.Height / 2 - Height / 2);
}

9
投票

我在我的主窗体中使用此代码,希望它有所帮助:

var form = new MyForm();
form.Show();
if (form.StartPosition == FormStartPosition.CenterParent)
{
    var x = Location.X + (Width - form.Width) / 2;
    var y = Location.Y + (Height - form.Height) / 2;
    form.Location = new Point(Math.Max(x, 0), Math.Max(y, 0));
}

5
投票

我发现当表单自动调整大小并动态修改时,手动设置位置是一些更复杂的情况下唯一可靠的选项。

但是,不是手动计算坐标,我建议使用现有方法:

this.CenterToParent();

3
投票

我找到了一个解决方案,它将无模式窗口位置置于父级位置,子窗口仍然可以被父窗口覆盖。你只需要打电话

f2.Show(f1);

将f2所有者设置为f1,f2将显示在f1的中心位置。

接下来你设置

f2.Owner = null;

你去了,f2是一个单独的窗口,具有正确的启动位置。


3
投票

我遇到了同样的问题,我最终还是这样做了:

protected override void OnActivated(EventArgs e) {
    if(this.Modal == false && this.StartPosition == FormStartPosition.CenterParent) {
        if(!(this.Owner is Form)) {
            // Center to the last form opened before this one
            int numforms = Application.OpenForms.Count;
            this.Owner = Application.OpenForms[numforms - 2];
        }
        this.CenterToParent();
        Application.DoEvents();
    }
    base.OnActivated(e);
}

用作:

MyForm form = new MyForm();
form.Show(this); // with or without

主要优点是它可以完成您的同事所期望的操作,而不需要在调用表单中进行任何操作。


2
投票

我意识到这是一个老问题,但我最近遇到了同样的问题,并且由于我不会进入的原因,我不想使用form.ShowDialog()方法而我的应用程序不是MDI应用程序,因此CenterParent方法没有任何效果。这就是我通过计算我想要居中的表单坐标并在主窗体的LocationChanged事件中触发新位置来解决问题的方法。希望这会帮助其他人解决这个问题。

在下面的示例中,父窗体称为MainForm,我希望在MainForm中居中的窗体称为pleaseWaitForm。

private void MainForm_LocationChanged(object sender, EventArgs e)
    {
        Point mainFormCoords = this.Location;
        int mainFormWidth = this.Size.Width;
        int mainFormHeight = this.Size.Height;
        Point mainFormCenter = new Point();
        mainFormCenter.X = mainFormCoords.X + (mainFormWidth / 2);
        mainFormCenter.Y = mainFormCoords.Y + (mainFormHeight / 2);
        Point waitFormLocation = new Point();
        waitFormLocation.X = mainFormCenter.X - (pleaseWaitForm.Width / 2);
        waitFormLocation.Y = mainFormCenter.Y - (pleaseWaitForm.Height / 2);
        pleaseWaitForm.StartPosition = FormStartPosition.Manual;
        pleaseWaitForm.Location = waitFormLocation;           
    } 

如果你有一个可调整大小的父表单,并且你希望你的子表单也可以在调整主表单大小时居中,理论上你应该能够将这个代码放在一个方法中,然后在LocationChanged和SizeChanged上调用该方法事件。


2
投票

JYelton的答案对我有用,但表单只在第一次调用Show()时居中。如果你想隐藏()表单,然后每次调用Show()时让它重新居中于父表单,你需要在表单中使用以下内容:

public new void Show(IWin32Window owner)
{
    base.Show(owner);

    if (Owner != null)
        Location = new Point(Owner.Location.X + Owner.Width / 2 - Width / 2,
            Owner.Location.Y + Owner.Height / 2 - Height / 2);
}

1
投票

运用

form.Show(this);

如果你第二次调用它会引发异常。手动设置位置似乎是唯一可靠的选项:/(最近CenterParent曾经工作过吗?)

© www.soinside.com 2019 - 2024. All rights reserved.