Открыть вторую win-форму асинхронно, но все еще вести себя как дочерняя по отношению к родительской форме? - PullRequest
15 голосов
/ 12 марта 2010

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

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

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

ProgressWindow.ShowDialog();

Когда эта команда встречается, основное внимание уделяется окну хода выполнения, и я предполагаю, что теперь это окно, основной цикл которого обрабатывается для событий. Недостатком является то, что он блокирует выполнение моей длительной операции в основной форме.

Если я открою окно прогресса, используя:

ProgressWindow.Show();

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

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

Ответы [ 3 ]

11 голосов
/ 12 марта 2010

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

Вот пример - в этом я предполагаю, что у вас есть две формы (Form1 и Form2). На Form1 я вытащил BackgroundWorker из панели инструментов. Затем я подключил событие RunWorkerComplete BackgroundWorker к обработчику событий в моей форме. Вот код, который обрабатывает события и показывает диалог:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        Thread.Sleep(5000);
        e.Result = e.Argument;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        var dlg = e.Result as Form2;
        if (dlg != null) {
            dlg.Close();
        }
    }

    private void button1_Click(object sender, EventArgs e) {
        var dlg = new Form2();
        this.backgroundWorker1.RunWorkerAsync(dlg);
        dlg.ShowDialog();
    }
}
3 голосов
/ 13 марта 2010

Я реализовал нечто очень похожее на это для другого проекта. Эта форма позволяет вам открыть модальное диалоговое окно из рабочего потока:

public partial class NotificationForm : Form
{
    public static SynchronizationContext SyncContext { get; set; }

    public string Message
    {
        get { return lblNotification.Text; }
        set { lblNotification.Text = value; }
    }

    public bool CloseOnClick { get; set; }

    public NotificationForm()
    {
        InitializeComponent();
    }

    public static NotificationForm AsyncShowDialog(string message, bool closeOnClick)
    {
        if (SyncContext == null)
            throw new ArgumentNullException("SyncContext",
                                            "NotificationForm requires a SyncContext in order to execute AsyncShowDialog");

        NotificationForm form = null;

        //Create the form synchronously on the SyncContext thread
        SyncContext.Send(s => form = CreateForm(message, closeOnClick), null);

        //Call ShowDialog on the SyncContext thread and return immediately to calling thread
        SyncContext.Post(s => form.ShowDialog(), null);
        return form;
    }

    public static void ShowDialog(string message)
    {
        //Perform a blocking ShowDialog call in the calling thread
        var form = CreateForm(message, true);
        form.ShowDialog();
    }

    private static NotificationForm CreateForm(string message, bool closeOnClick)
    {
        NotificationForm form = new NotificationForm();
        form.Message = message;
        form.CloseOnClick = closeOnClick;
        return form;
    }

    public void AsyncClose()
    {
        SyncContext.Post(s => Close(), null);
    }

    private void NotificationForm_Load(object sender, EventArgs e)
    {
    }

    private void lblNotification_Click(object sender, EventArgs e)
    {
        if (CloseOnClick)
            Close();
    }
}

Чтобы использовать, вам нужно установить SyncContext где-то в вашем потоке GUI:

NotificationForm.SyncContext = SynchronizationContext.Current;
3 голосов
/ 12 марта 2010

Другой вариант:

Используйте ProgressWindow.Show() и самостоятельно реализуйте поведение модального окна. parentForm.Enabled = false, разместите форму самостоятельно и т. Д.

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