How to continue executing code after calling ShowDialog()

后端 未结 7 784
走了就别回头了
走了就别回头了 2020-12-17 10:58

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.

相关标签:
7条回答
  • 2020-12-17 11:17

    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.

    0 讨论(0)
  • 2020-12-17 11:23

    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

    0 讨论(0)
  • 2020-12-17 11:25

    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 ...
    }
    
    0 讨论(0)
  • 2020-12-17 11:26

    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?

    0 讨论(0)
  • 2020-12-17 11:32

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-17 11:36
    • 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.

    0 讨论(0)
提交回复
热议问题