C # / WinForms: ShowDialog и последующее Показать в форме - PullRequest
2 голосов
/ 25 февраля 2011

По причинам, которые я считаю здесь неактуальными, у меня есть один или несколько потоков, которые взаимодействуют с одним экземпляром пользовательского интерфейса (формы).

В рабочих потоках мне нужно сообщать о прогрессе или вводить данные или простые варианты. Все они происходят от взаимодействия пользователя с пользовательским интерфейсом и, конечно же, для M $ .NET все пользовательские интерфейсы выполняются в основном потоке.

Очевидно, что мне нужно обрабатывать синхронизацию потоков между потоками пользовательского интерфейса (основным) и рабочими. Я делаю это, правильно проверяя InvokeRequired и компанию.

Существует множество постов и статей, в которых обсуждаются несоответствия и тонкости в InvokeRequired, IsHandleCreated, IsDisposed и т. Д., Поэтому я не буду об этом говорить.

Я просто должен сказать, что мой пользовательский интерфейс, который является просто формой, должен был отображаться как модальная или немодальная форма, в зависимости от желания вызывающего абонента.

Один мог просто UI.Warn( "Warning!" ), а другой мог UI.Question( "Make a choice:", options... ).

Теперь рассмотрим следующий отрывок из документации M $ DN:

Form.ShowDialog Метод:

В отличие от немодальных форм, метод Close не вызывается .NET Framework, когда пользователь нажимает кнопку закрытия формы ...

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

Но это так!

Когда форма возвращается из ShowDialog( ), ее Handle просто отбрасывается, полагая, что когда она снова понадобится, будет вызван ShowDialog( ) и дескриптор будет воссоздан.

Я понятия не имею, почему M $ вещи нужны для этого, но я просто подумал, что смогу получить ту же самую форму, которая будет отлично работать, как модальный или немодальный без проблем. Документы M $ DN ничего не говорят о том, что это запрещено (или я слишком пьян, чтобы найти это)!

Ну, в конце концов, это относительно простой (и грязный) способ исправить это.

var r = ShowDialog( );

// Handle thrown away aftr "ShowDialog()" supposing the
// next one will recreate it.
if ( !this.IsHandleCreated )
{
    // Force "Handle" recreation here, while in the main thread,
    // before any "Show()" happens.
    CreateHandle( );
}

return r;

Это работает, но мне интересно, не должно ли быть приличного способа достичь того же конца. (Возможно, программирование в чем-то, что не несет в себе никакого предела совместимости с предками, как это делает .NET по-прежнему ...)

1 Ответ

3 голосов
/ 25 февраля 2011

Вы уверены, что у вас нет этого отсталого?Я создал простую пустую форму для использования в качестве модального диалогового окна, а затем протестировал ее с простой формой, в которой просто есть кнопка, отображающая диалоговое окно.

public partial class Form1 : Form
{
    private MyDialog theDialog;
    public Form1()
    {
        InitializeComponent();
        theDialog = new MyDialog();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        theDialog.ShowDialog();
    }
}

Я могу многократно отображать диалоговое окно без проблем.

Теперь, если я позвоню theDialog.Show(), закрою его и попытаюсь показать снова, я получу ObjectDisposedException.

Итак, документация верна: ShowDialog делаетне звоните Form.Close, тогда как Show явно делает.

РЕДАКТИРОВАТЬ:

Документация для Form.Close говорит вам, что у вас естьсделать, если вы хотите предотвратить уничтожение формы:

Вы можете предотвратить закрытие формы во время выполнения, обработав событие Closing и установив свойство Cancel объекта CancelEventArgs, переданного в качестве параметрак вашему обработчику событий.

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

public partial class Form1 : Form
{
    private MyDialog theDialog;
    public Form1()
    {
        InitializeComponent();
        theDialog = new MyDialog();
        theDialog.FormClosing += new FormClosingEventHandler(theDialog_FormClosing);
    }

    void theDialog_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
        theDialog.Hide();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (theDialog.Visible)
        {
            theDialog.BringToFront();
        }
        else
        {
            theDialog.ShowDialog();
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (theDialog.Visible)
        {
            theDialog.BringToFront();
        }
        else
        {
            theDialog.Show();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...