让方法在子构造器的InitializeComponent完成后运行,而无需在子类中隐式调用

本文关键字:子类 调用 构造器 方法 InitializeComponent 运行 | 更新日期: 2023-09-27 18:04:53

我不确定这是否可能,但我希望能够做的是让Parent基类的所有子类运行在基类中定义的方法,而无需在子类中显式调用它。

换句话说,我想实现的是这样的:

public class Parent
{
    public Parent()
    {
       InitializeComponent();
       Setup(); // not run here if this instance is a child of parent
    }
    protected void Setup()
    {
        // code that depends on InitializeComponent being called in
        // both the parent and any Child's classes 
    }
}
public class Child : Parent
{
    public Child()
    {
       InitializeComponent();
       //Setup(); is invoked here, without having to explicitly 
       // invoke in all children of Parent
    }
}

是否有一种模式可以启用这种行为,或者也许面向方面编程是实现这一目标的一种方式?

让方法在子构造器的InitializeComponent完成后运行,而无需在子类中隐式调用

你可以重写父表单的Form.OnLoad方法;它保证在表单显示之前被调用。

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

我想你只是想重写OnLoad方法:

public class Parent
{
    public Parent()
    {
       InitializeComponent();
    }
    protected override void OnLoad(EventArgs e)
    {
        // put initialization code here
        base.OnLoad(e);
    }
}

在父组件和子组件初始化时调用。
不要忘记调用base.OnLoad,以便Load事件处理程序(如果有的话)接收事件。

Child的构造函数将自动调用Parent的构造函数(实际上,在它自己的代码被调用之前),所以在上面的情况下,Setup将始终在Child类中被调用(InitializeComponent将被调用两次)。

LoadOnLoad事件中运行代码通常是最糟糕的解决方案。

如果你想在表单加载后运行代码一次,你可以使用Shown事件,否则表单看起来滞后和无响应,你有长时间运行的代码(控件一个接一个地显示)

如果你真的想在子构造函数之后但在加载事件之前运行代码,重写OnHandleCreated是你最好的选择。

然而,(至少)有一件事是行不通的。我有一个表单基类,它设置了一个特定的启动位置/大小,而不管子表单定义了什么。我所做的每一次努力都失败了,或者表单在错误的位置有一瞬间是可见的。我是这样解决的:

public class MyForm : Form
{
    private Size defaultSize;
    public MyForm()
    {
        InitializeComponent();
        this.defaultSize = this.Size;
        this.fireOnBeforeLoad = true;
    }
    public new void ResumeLayout(bool performLayout)
    {
        base.ResumeLayout(performLayout);
        if (fireOnBeforeLoad)
        {
            fireOnBeforeLoad = false;
            OnBeforeLoad();
        }
    }
    protected virtual void OnBeforeLoad()
    {
        form.WindowState = FormWindowState.Normal;
        form.Size = defaultSize;
        form.FormBorderStyle = FormBorderStyle.FixedDialog;
        var area = Screen.FromControl(form).WorkingArea;
        form.Size = defaultSize;
        form.Location = new System.Drawing.Point(
            (int)(area.Width - form.Width) / 2, 
            (int)(area.Height - form.Height) / 2);
    }
}

这里是棘手的部分:在设置大小之后,它在加载过程中的某个点以某种方式被恢复。如果调用Screen.FromControl(form),也会发生同样的事情。我想是因为Screen.FromControl最终调用Screen.FromHandle,这将导致句柄被创建。但我认为它也做了其他事情,因为如果我在OnHandleCreated方法中运行上面的代码(当然是在调用base.OnHandleCreated之后),它不会得到想要的结果。因此,我在Screen.FromControl之后再次设置大小,最后一行只是在屏幕上的窗体中心