-
Notifications
You must be signed in to change notification settings - Fork 129
WPF ShowDialogAsync
Note: The open-source application Waf DotNetApiBrowser shows the techniques described in this article.
This article shows how to implement an async variant of ShowDialog and why this has an advantage in some scenarios.
Show a WPF dialog and then fill it with asynchronously loaded data. During loading the dialog should show some progress indication and when the loading is completed the dialog will be filled with the data.
Show the WPF dialog and then load the data within the Loaded event handler.
The disadvantage of the straight forward implementation is that loading of the data will be done in the code-behind part of the View (e.g. Loaded event handler). ShowDialogAsync is an alternative which allows a class (e.g. Controller) to be responsible for showing the dialog and to load the data.
The following sample starts to download some content from the internet and shows a WPF dialog at the same time. When the download completes then the dialog is updated with the content. If the user closes the dialog before the download has completed, then the CancellationTokenSource is used to cancel the download.
private async Task ShowDialogAndLoadDataAsync(object ownerWindow)
{
var cancellationSource = new CancellationTokenSource();
var downloadTask = DownloadAsync(cancellationSource.Token);
var customDialog = new CustomDialog();
var dialogTask = customDialog.ShowDialogAsync(ownerWindow);
var firstCompletedTask = await Task.WhenAny(downloadTask, dialogTask);
if (firstCompletedTask == downloadTask)
{
customDialog.DataContext = await downloadTask;
}
else
{
cancellationSource.Cancel();
}
try
{
await Task.WhenAll(downloadTask, dialogTask);
}
catch (OperationCanceledException)
{
// Ignore this exception
}
}
private async Task<string> DownloadAsync(CancellationToken cancellationToken)
{
var httpClient = new HttpClient();
var httpClientTask = httpClient.GetAsync("http://www.google.com",
cancellationToken);
await Task.Delay(2000, cancellationToken); // Simulate some visible delay
var httpResult = await httpClientTask;
return await httpResult.Content.ReadAsStringAsync();
}
This part shows the implementation of ShowDialogAsync.
public partial class CustomDialog : Window
{
private TaskCompletionSource<object> showDialogCompletionSource;
public CustomDialog()
{
InitializeComponent();
Closed += OnClosed;
}
public Task ShowDialogAsync(object owner)
{
if (showDialogCompletionSource != null)
throw new InvalidOperationException("The dialog is already shown.");
showDialogCompletionSource = new TaskCompletionSource<object>();
Dispatcher.BeginInvoke(DispatcherPriority.Send, (Action)(() =>
{
Owner = owner as Window;
ShowDialog();
}));
return showDialogCompletionSource.Task;
}
private void OnClosed(object sender, EventArgs e)
{
showDialogCompletionSource.SetResult(null);
showDialogCompletionSource = null;
}
}