Программирование WinForms - проблема модальных и немодальных форм - PullRequest
6 голосов
/ 14 мая 2010

У меня проблема с модальностью форм под C # .NET. Допустим, у меня есть основная форма # 0 (см. Изображение ниже). Эта форма представляет собой основную форму заявки, где пользователь может выполнять различные операции. Однако время от времени возникает необходимость открывать дополнительную немодальную форму для выполнения дополнительных основных функций поддержки приложений. Допустим, это форма № 1 на изображении. В этой форме № 1 могут быть открыты несколько дополнительных модальных форм друг на друге (форма № 2 на рисунке), и в конце, есть диалоговое окно прогресса, показывающее длительный ход операции и состояние, которое может занять от нескольких минут до нескольких часов. Проблема в том, что основная форма # 0 не реагирует, пока вы не закроете все модальные формы (# 2 на изображении). Мне нужно, чтобы основная форма № 0 работала в этой ситуации. Однако, если вы откроете немодальную форму в форме № 2, вы можете работать как с модальной формой № 2, так и с вновь созданной немодальной формой. Мне нужно такое же поведение между основной формой # 0 и формой # 1 со всеми ее дочерними формами. Является ли это возможным? Или я что-то не так делаю? Может быть, есть какой-то обходной путь, я действительно не хотел бы менять все вызовы ShowDialog на Show ...

Изображение http://img225.imageshack.us/img225/1075/modalnonmodalproblem.png

Ответы [ 5 ]

12 голосов
/ 14 мая 2010

Модальные формы делают именно то, что означает "модальные", они отключают все другие окна в приложении. Это довольно важно, ваша программа находится в несколько опасном состоянии. У вас есть кусок кода, который ожидает закрытия диалога. Действительно плохие вещи могут произойти, если эти другие окна не были отключены. Как пользователь мог снова запустить модальное диалоговое окно, теперь ваш код вложен дважды. Или она могла закрыть окно владельца окна, теперь оно внезапно исчезает.

Это именно те проблемы, с которыми вы столкнетесь, если вызовите Application.DoEvents () внутри цикла. Это один из способов заставить форму вести себя модально, не отключая другие окна. Например:

    Form2 mDialog;

    private void button1_Click(object sender, EventArgs e) {
        mDialog = new Form2();
        mDialog.FormClosed += (o, ea) => mDialog = null;
        mDialog.Show(this);
        while (mDialog != null) Application.DoEvents();
    }

Это опасно .

Конечно, лучше всего использовать модальные формы так, как они были разработаны, чтобы избежать неприятностей. Если вам не нужна модальная форма, просто не делайте ее модальной, используйте метод Show (). Подпишитесь на событие FormClosing, чтобы узнать, что он собирается закрыться:

    private void button1_Click(object sender, EventArgs e) {
        var frm = new Form2();
        frm.FormClosing += new FormClosingEventHandler(frm_FormClosing);
        frm.Show();
    }

    void frm_FormClosing(object sender, FormClosingEventArgs e) {
        var frm = sender as Form2;
        // Do something with <frm>
        //...
    }
3 голосов
/ 14 мая 2010

Первое, что приходит на ум, будет что-то вроде этого. Вы можете отключить форму 1, когда вы запускаете форму 2 и затем форма 1 обрабатывает закрытое событие второй формы, чтобы снова включить ее. Вы не открыли бы модал 2, используя диалог show.

Имейте в виду, что с точки зрения пользователя это будет довольно громоздко, вы можете посмотреть на создание приложения MDI, чтобы получить все окна внутри одного контейнера.

0 голосов
/ 05 августа 2012

На самом деле ответ очень прост. Попробуйте

newForm.showDialog();

Откроется новая форма, в то время как родительская форма недоступна.

0 голосов
/ 14 мая 2010

Мне кажется, вы могли бы использовать приложение MDI, задав для свойства Form # 0 IsMdiContainer значение true.

Тогда вы можете сделать что-то похожее:

public partial class Form0 {
    public Form0 {
        InitializeComponent();
        this.IsMdiContainer = true; // This will allow the Form #0 to be responsive while other forms are opened.
    }

    private void button1_Click(object sender, EventArgs e) {
        Form1 newForm1 = new Form1();
        newForm1.Parent = this;
        newForm1.Show();
    }
}

Использование ShowDialog () , как вы указали в своем вопросе, сделает все формы Modal = true .

По определению модальная форма:

Когда форма отображается модально, ввод данных (нажатие клавиатуры или мыши) невозможен, за исключением объектов в модальной форме. Программа должна скрыть или закрыть модальную форму (обычно в ответ на какое-либо действие пользователя), прежде чем может произойти ввод в другую форму. Формы, отображаемые модально, обычно используются в диалоговых окнах приложения.

Вы можете использовать это свойство [( Modal )], чтобы определить, была ли форма, полученная из метода или свойства, отображена модально.

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

Если вы не хотите, чтобы ваша основная форма была контейнером MDI, то, возможно, использование многопоточности является одним из решений с помощью простого BackgroundWorker класса, который является ключом к тому, чего вы хотите достичь. Таким образом, это выглядит как дизайнерский запах ...

  • Что вы хотите сделать, кроме того, что ваша основная форма должна быть адаптивной и т. Д.
  • Что ты должен делать?

Объясняя, что вы должны делать, мы можем полностью направить вас в правильное или, по крайней мере, возможно, лучшее направление.

0 голосов
/ 14 мая 2010

Ваша основная форма не будет реагировать до тех пор, пока какие-либо модальные диалоги, находящиеся в том же пространстве процесса, не будут закрыты. Для этого нет работы.

...