Как продолжить выполнение кода после вызова ShowDialog()

метод Form.ShowDialog() заставляет код останавливаться до тех пор, пока вновь вызываемая форма не будет закрыта. Мне нужен код для продолжения работы после вызова метода ShowDialog(). Я googled и читал об использовании backgroundworker? Но это первый раз, когда я слышал об этом и никогда не использовал его раньше.

Form2 form2this = new Form2();
form2this.ShowDialog();
MessageBox.Show("Something");

Этот код запускается после нажатия кнопки, как я могу по-прежнему вызывать ShowDialog, чтобы пользователь не взаимодействовал с основной формой, но все же позволял основной форме продолжать свою работу?

Извините, если это обсуждалось, но все, что я нашел, кажется чрезвычайно сложным для выполнения такой простой задачи. Я действительно удивлен, что он не включен в метод SHowDialog. например ShowDialog(). Продолжить было бы круто.

Ответ 1

  • Если вы просто хотите, чтобы код продолжался, а не блокировался, пока всплывающее окно не закрыто, используйте Show вместо ShowDialog.

  • Если у вас есть какое-то действие, которое вы хотите, чтобы родительская форма выполнялась во время создания дочерней формы, тогда да, было бы целесообразно использовать BackgroundWorker (или просто вручную запустить новую тему/задачу). Было бы полезно узнать больше о том, что это за задача. Если вам нужно взаимодействовать с основной формой или дочерней формой, то это кажется мне неприятным; если вам просто нужно выполнить некоторую фоновую задачу без взаимодействия с пользовательским интерфейсом, тогда это правильная линия мысли.

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

Ответ 2

Пока вы выполняете асинхронные операции за время открытия модального диалога, вы можете сделать это так же просто, как показано ниже, если button1_Click() является обработчиком события для кнопки.

private async void button1_Click(object sender, EventArgs e)
{
    // create and display modal form
    Form2 modalForm = new Form2();
    BeginInvoke((Action)(() => modalForm.ShowDialog()));

    // do your async background operation
    await DoSomethingAsync();

    // close the modal form
    modalForm.Close();
}


private async Task DoSomethingAsync()
{
    // example of some async operation....could be anything
    await Task.Delay(10000);
}

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

Ответ 3

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

Ответ 4

Запустите асинхронный вызов, чтобы показать модальный. Вот пример в wpf:

private Window waitView;

/// <summary>
/// Closes a displayed WaitView from code.
/// </summary>
public void CloseWaitView()
{
  if(waitView != null)
  {
     // Work on the gui Thread of waitView.
     waitView.Dispatcher.Invoke(new Action(() => close()));
  }
}

/// <summary>
/// Closes a displayed WaitView and releases waitView-Instance.
/// </summary>    
private void close()
{
   waitView.Close();
   waitView = null;
}   

/// <summary>
/// Showes a modal WaitView (Window).
/// </summary>
public void ShowWaitView()
{
  // instance a new WaitViewWindow --> your Window extends Window-Class
  waitView = new WaitViewWindow();

  // prepare a operation to call it async --> your ShowDialog-call
  var asyncCall = new Action(() => waitView.Dispatcher.Invoke(
                                   new Action(() => waitView.ShowDialog())
                             ));

  // call the operation async

  // Argument 1 ar:
  // ar means IAsyncResult (what should be done, when come back from ShowDialog -->     
  // remove view memory with set waitView to null or ... dispose

  // the second argument is an custom parameter you can set to use in ar.AsyncState
  asyncCall.BeginInvoke(ar => waitView = null, null);

  // all from here is done during ShowDialog ...
}

Ответ 5

Это мой путь, такой уродливый, но у меня нет лучшей идеи.

private void AppUiMain_Shown(object sender, EventArgs e)
{
    var loading = new AppUiLoading();
    loading.Shown += (o, args) =>
    {
        bool isLoading = true;
        loading.Top = (int)(loading.Top * 1.16);

        Application.DoEvents();//refresh ui

        EventHandler ehr = null;
        EventHandler ehe = null;
        ehr = (ss, ee) =>
        {
            App.Instance.Ready -= ehr;
            App.Instance.Error -= ehe;
            isLoading = false;
        };
        ehe = (ss, ee) =>
        {
            loading.Text = "Error";
            loading.ShowAbortButton("Error occur");
        };
        App.Instance.Error += ehe;
        App.Instance.Ready += ehr;
        InitApp();

        //HACK: find a better way to `refresh' main form
        Application.DoEvents();
        this.Height++;
        this.Height--;

        //HACK: find a better way to keep message looping on ShowDialog
        while (isLoading)
            Application.DoEvents();

        loading.Close();
    };
    loading.ShowDialog(this);
}

Ответ 6

Продолжить выполнение кода без закрытия модального диалога WindowsFormsSynchronizationContext.Current.Post(- = > { "Ваш код" }, null); может быть использован. Здесь вы можете найти более подробную информацию -

http://newapputil.blogspot.in/2015/05/continue-executing-code-after-calling.html

Ответ 7

Я предполагаю следующее решение для async ShowDialog:

public bool DialogResultAsync
{
    get;
    private set;
}

public async Task<bool> ShowDialogAsync()
{
    var cts = new CancellationTokenSource();
    // Attach token cancellation on form closing.
    Closed += (object sender, EventArgs e) =>
    {
        cts.Cancel();
    };
    Show(); // Show message without GUI freezing.
    try
    {
        // await for user button click.
        await Task.Delay(Timeout.Infinite, cts.Token);
    }
    catch (TaskCanceledException)
    { } 
}

public void ButtonOkClick()
{
    DialogResultAsync = true;
    Close();
}

public void ButtonCancelClick()
{
    DialogResultAsync = false;
    Close();
}

И в основной форме вы должны использовать этот код:

public async void ShowDialogAsyncSample()
{
    var msg = new Message();
    if (await msg.ShowDialogAsync())
    {
        // Now you can use DialogResultAsync as you need.
        System.Diagnostics.Debug.Write(msg.DialogResultAsync);
    }
}