Запуск метода после завершения InitializeComponent дочернего конструктора без косвенного вызова в дочерних классах - PullRequest
0 голосов
/ 10 августа 2011

Я не уверен, возможно ли это или нет, но я хотел бы, чтобы все дочерние элементы базового класса 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
    }
}

Есть ли шаблон, который может включить это поведение, или, возможно, Аспектно-ориентированное программированиебыть способ достичь этого?

Ответы [ 4 ]

4 голосов
/ 10 августа 2011

Вместо этого вы можете переопределить метод Form.OnLoad родительской формы;он гарантированно будет вызван перед показом формы.

protected override void OnLoad(EventArgs e)
{
    Setup();

    base.OnLoad(e);
}
1 голос
/ 10 августа 2011

Я думаю, вы просто хотите переопределить OnLoad метод:

public class Parent
{
    public Parent()
    {
       InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        // put initialization code here

        base.OnLoad(e);
    }
}

Вызывается, когда инициализируются как родительский, так и дочерний компоненты.
Не забудьте вызвать base.OnLoad, чтобы обработчики событий Load, если они есть, получили событие.

0 голосов
/ 10 сентября 2015

Запуск кода в событии Load или OnLoad часто является худшим решением.

Если вы хотите запустить код один раз после загрузки формы, вы можете использовать событие 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, последняя строка просто центрирует форму на экране.

0 голосов
/ 10 августа 2011

Конструктор Child будет автоматически вызывать конструктор Parent (фактически, до того, как будет вызван его собственный код), поэтому в вашей ситуации выше, Setup всегда вызывается в классе Child (и InitializeComponent будет вызываться дважды).

...