Закрытие формы во время конструктора - PullRequest
45 голосов
/ 18 июня 2010

Можно ли закрыть форму во время выполнения конструктора (или просто остановить ее показ на этом этапе)?

У меня есть следующий код:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Close();
        }
    }
}

, который генерирует исключение ObjectDisposedException в Main (), здесь:

    static void Main()
    {            
        ...

        // Following line errors
        Application.Run(new MyForm());
    }

Я пытался проверить результат MyForm следующим образом:

static void Main()
{            
    ...

    MyForm frm = new MyForm();
    if (frm != null)
    {
        // Following line errors
        Application.Run(frm);
    }
}

Но это, похоже, не помогает. Может кто-нибудь сказать мне способ обойти это, пожалуйста? Может быть, способ проверить форму, чтобы увидеть, если она все еще существует?

Ответы [ 9 ]

83 голосов
/ 19 декабря 2011

Вызов Close из конструктора формы невозможен, так как он вызовет Dispose в форме, которая еще не была создана. Чтобы закрыть форму после создания, назначьте анонимный обработчик события Load , которое закрывает форму до ее первого отображения:

public partial class MyForm : Form
{
    public MyForm()
    {
        if (ShouldClose())
        {
            Load += (s, e) => Close();
            return;
        }

        // ...
    }

    // ...
}
20 голосов
/ 18 июня 2010

Единственное, что вы можете сделать, это установить флаг, чтобы закрыть его в конструкторе, а затем закрыть его в событии Shown.Конечно, если вы делаете это, имеет смысл переместить код, чтобы определить, должен ли он быть закрыт там в первую очередь.

17 голосов
/ 22 июля 2011

Хорошо работает следующее:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Shown += new EventHandler(MyForm_CloseOnStart);
        }
    }

    private void MyForm_CloseOnStart(object sender, EventArgs e)
    {
        this.Close();
    }
}
8 голосов
/ 18 июня 2010

Когда вы вызываете Close () для формы, внутренне она удаляет форму и освобождает любые управляемые ресурсы.Когда вы сделаете это:

Application.Run(new MyForm());

Вы, вероятно, получите исключение ObjectDisposedException.Что вам нужно сделать, это установить видимость формы через свойство:

Application.Run(new MyForm() { Visible = false });

Просто убедитесь, что вы удалили вызов Close () в конструкторе, или даже переместите туда присвоение свойства.

3 голосов
/ 18 апреля 2012

Я обнаружил, что добавление обработчика к событию 'Load' лучше, так как диалоговое окно вообще никогда не отображается. С событием «Показано» вы можете кратко увидеть, что диалоговое окно открывается, а затем закрывается, что может сбивать с толку:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Load += MyForm_CloseOnStart;
        }
    }

    private void MyForm_CloseOnStart(object sender, EventArgs e)
    {
        this.Close();
    }
}
3 голосов
/ 18 июня 2010

Можете ли вы сделать MyFunc статичным? а затем сделать что-то вроде:

static void Main() 
{             
    ... 
    if (MyForm.MyFunc())
    {
        Application.Run(new MyForm()); 
    }
} 

это, по сути, даст вам тот же контроль над тем, будет ли форма построена или нет?

2 голосов
/ 15 июля 2018

Environment.Exit(...) у меня работает (без мерцания окна):

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (weShouldClose)
        {
            Environment.Exit(0);
        }
    }
}
2 голосов
/ 30 октября 2013

Я думаю, что не стоит закрывать форму в конструкторе. Если вы сделаете это, пользователи вашей формы не будут знать, показывать ли ShowDialog или нет.

Следующий код будет вполне нормальным использованием:

// in the parent form:
public void ShowMyForm()
{
    MyForm form = new MyForm();
    form.propertyA = ...;
    from.propertyB = ...;
    DialogResult dlgResult = form.ShowDialog(this);
    ProcessDialogResult(dlgResult);
}

Если вы решили в конструкторе, должна ли форма отображаться, вам нужно будет добавить код после построения, чтобы решить, вызывать ли ShowDialog или нет и обрабатывать ли результат диалога.

Кроме того, вы уверены, что изменение свойств никогда не повлияет на то, должна ли форма отображаться или нет? Также после будущих изменений?

Во время строительства форма еще не показана / не открыта. Поэтому я боюсь, что Close() не делает то, что вы ожидаете.

Аккуратный метод - делать проверки, которые вы хотели сделать в конструкторе в Form_Load. Добавьте обработчик событий для загрузки формы и выполните свои проверки в обработчике событий. Используйте свойство DialogResult, чтобы указать, что вы решили не показывать форму.

private void FormMain_Load (object sender, EventArgs e)
{
    if (FormShouldNotLoad())
    {
        this.DialogResult = System.Windows.Forms.DialogResult.Abort;
        Close();
        // Warning, this does not work, see below, (but we're almost there!)
    }
}

Пользователь кода может проверить результат диалога:

// in the parent form:
public void ShowMyForm()
{
    MyForm form = new MyForm();
    form.propertyA = ...;
    from.propertyB = ...;
    DialogResult dlgResult = form.ShowDialog(this);
    switch (dlgResult)
    {
        case System.Windows.Forms.DialogResult.Abort:
            ProcessFormNotLoaded();
            break;
        case System.Windows.Forms.DialogResult.OK:
            ProcessFormOk();
            break;
        // etc.
    }
}

Однако вызов Close () в обработчике событий для загрузки формы не будет работать, потому что Close() может быть правильно вызван только после завершения загрузки.

Следовательно, вместо вызова Close(), вы должны BeginInvoke функцию Close (), поэтому функция Close будет вызываться после завершения загрузки:

private void FormMain_Load (object sender, EventArgs e)
{
    if (FormShouldNotLoad())
    {
        this.DialogResult = System.Windows.Forms.DialogResult.Abort;
        // invoke the Close function after Load completed
        this.BeginInvoke(new MethodInvoker( () => this.CancelLoading())
    }
}
0 голосов
/ 30 октября 2014

Если вы хотите, чтобы ваше окно никогда не было видно
(нет мерцающих окон, которые открываются на мгновение, а затем исчезают) :

public new void Show()
{
    if (MyFunc())
        base.Show();
    else
        ; // dispose or whatever
}

Хотя Show(...) имеет 2 перегрузки и ShowDialog(...) также имеет 2.
Не работает для главной формы, открываемой через Application.Run().Но кто бы это сделал?Кроме того, есть также способ открыть основную форму без использования Application.Run().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...