-1

I am trying to open a loading window while the else code keeps executing in the background, and close it whenever required (without threading).

Something like this:

LoadingWindow.ShowDialog();
Thread.Sleep(2000);     //Simulates slowness
AnotherForm.ShowDialog();
LoadingWindow.Close(); //After AnotherForm displayed.

I can't use only LoadingWindow.Show(); to continue execution because LoadingWindow will not display correctly till the code after LoadingWindow.Show(); gets executed.

I have a custom Async ShowDialog method ShowDialogAsync();, but the problem is await will not reach till the AnotherForm.ShowDialog(); get completed.

I tried:

var LoadingTask = LoadingWindow.ShowDialogAsync();
Thread.Sleep(2000);     //Simulates slowness
//await AnotherForm.ShowDialogAsync();    //Not worked
//AnotherForm.ShowDialog();               //Not worked
//AnotherForm.Show();                     //Not Worked
LoadingWindow.Close();
await LoadingTask;

This can only be used with await for simple methods:

var LoadingTask = LoadingWindow.ShowDialogAsync();
var data = await LoadDataAsync();
LoadingWindow.Close();
await LoadingTask;

//Sample simple method
private void LoadDataAsync()
{
        await Task.Delay(2000);
        return 10;
}

ShowDialogAsync:

public static async Task<DialogResult> ShowDialogAsync(this Form @this)
{
    await Task.Yield();
    if (@this.IsDisposed)
        return DialogResult.OK;
    return @this.ShowDialog();
}
Thrainder
  • 77
  • 1
  • 10
  • Could you include the custom `ShowDialogAsync` method in the question? – Theodor Zoulias Jun 26 '21 at 10:18
  • @TheodorZoulias I added as requested. It's a simple return method using `Task.Yield();` and you can give me an up if this question makes sense to you. – Thrainder Jun 26 '21 at 13:51
  • Is it copied from [this](https://stackoverflow.com/questions/33406939/async-showdialog/33411037#33411037) answer (by noseratio)? – Theodor Zoulias Jun 26 '21 at 13:57
  • Btw your question is not very clear regarding what you are trying to achieve. Can you write in more details, step by step, what is the desirable sequence of events? – Theodor Zoulias Jun 26 '21 at 14:02
  • 4
    Since you have long running non-UI work to do the solution *is to do it in a background thread*, not in the UI thread. You say you don't want to, but that's simply how the platform is designed for you to do that. Just saying you don't want to doesn't change that. The UI thread is for updating your UI, not doing long running non-UI work, and you're just going to create tons of problems for yourself by not following that design. – Servy Jun 26 '21 at 15:28
  • 1
    `ShowDialogAsync` looks like Windows Forms method. But tag is WPF. What's real type of the project? – aepot Jun 26 '21 at 21:33
  • 2
    @aepot I added the [wpf](https://stackoverflow.com/questions/tagged/wpf) tag because of the `LoadingWindow` field, that carries the wpf nomenclature. But I am not sure, it may be WinForms. Hopefully the OP will clarify. – Theodor Zoulias Jun 27 '21 at 05:36

1 Answers1

2

As the author of the linked answer, I feel summoned :) I think I understand the problem you're running into. Try the following, see the comments inline:

// on the main message loop of the UI thread
var LoadingTask = LoadingWindow.ShowDialogAsync();

// dialog isn't shown here yet, yield to the message loop
await Task.Yield();

// now ShowDialog has been called and the dialog is visible,
// we're now on the nested message loop run by ShowDialog
await Task.Run(() => 
{
  // on a thread pool thread, do the work here
  Thread.Sleep(2000);
});

// on the UI thread, still on the nested message loop of ShowDialog
// close the dialog
LoadingWindow.Close();

// still on the nested message loop, despite the window has closed
await LoadingTask;

// this is when ShowDialog method has returned,
// and we're back to the main message loop of the UI thread

Don't use Thread.Sleep or any other long-running synchronous code on the UI thread, even when experementing. The dialog is shown asynchronously. Thread.Sleep blocks the message loop and the ShowDialog isn't getting a chance to execute when you expect it to.

It helps to understand what Task.Yield actually does behind the sence in this case. The continuation code after await Task.Yield() won't get magically executed until after some future iterations of the message loop. And there will be no future iterations while you're making a blocking call on the UI thread. That's what the thread pool and Task.Run are for.

Otherwise, the continuation callback will be just sitting in the queue managed by WindowsFormsSynchronizationContext or DispatcherSynchronizationContext.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • [Asynchronous programming](https://learn.microsoft.com/en-us/dotnet/csharp/async), for reference. – aepot Jun 27 '21 at 07:29