-->

How to continue executing code after calling ShowD

2019-02-16 08:08发布

问题:

the Form.ShowDialog() method causes the code to be halted until the newly called form is closed. I need the code to continue running after the ShowDialog() method is called. I googled and read about using backgroundworker? But that is the first time i have heard of that and never used it before.

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

This code gets executed after clicking a button, how can i still call ShowDialog to prevent the user from interacting with the main form but still allowing the main form to continue with its work?

Sorry if its been discussed but everything i found seems extremely difficult to perform such a simple task. I am actually surprised its not included in the SHowDialog method. for instance ShowDialog().Continue would be cool.

回答1:

  • If you just want the code to continue on instead of blocking until the popup is closed consider using Show instead of ShowDialog.

  • If you have some action that you want to have the parent form doing while the child form is up, then yes, it could be appropriate to use a BackgroundWorker (or just manually starting a new Thread/Task). It would be helpful to know more about what that task is though. If you need to interact with the main form, or the child form, then that seems like trouble to me; if you just need to do some background task with no UI interaction then this is the right line of thought.

  • Another possibility is that what you want to do really just should be something done in the child form, rather than the parent form.



回答2:

As long as you do asynchronous operations during the time that the modal dialog is opened, you can do it as simply as shown below, assuming button1_Click() is the event handler for a button.

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);
}

I found that when I used the solution that suggested to use Show(), I could end up in cases where the dialog I wanted to be modal would end up behind the main form, after switching back and forth between apps. That never happens when I use the solution above.



回答3:

Is there any reason why you can't have this code as part of the Form2 class? Or use a non-modal dialog? You could use a background worker or even something simple like a timer, but seems like overkill?



回答4:

Run an async call to show modal. Here an example in 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:

This is my way, so ugly but i have no better idea.

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:

To continue code execution without closing modal dialog WindowsFormsSynchronizationContext.Current.Post(-=> {"Your code"}, null); can be used. Here you can find more detail -

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



回答7:

I suppose next solution for 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();
}

And in main form you must use this code:

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);
    }
}