Florian Koch
Florian Koch

Reputation: 1502

ShowMetroDialogAsyncdoesn't show the dialog when waiting for the task

I tried to implement a DialogManager like described here. I'm not using caliburn, so I refactored a bit, and also it's no longer SimpleDialog but CustomDialog, but there weren't big changes.

So now when I click a button that calls DialogManager.ShowDialog and wait for the resulting task with task.Wait() the application just freezes (as aspected for wait) but without showing the dialog. I tried to debug, but it works alright until the line

await Application.Current.Windows.OfType<MetroWindow>().First().ShowMetroDialogAsync(dialog);

. dialog is a valid BaseMetroDialog and i get the right window from the Application.Cur... call. It also happens when I'm just calling ShowMessageAsync, so the problem seems to be in the connection of the call and the waiting for the task. Is there no way to really block the following execution (forcing the dialog to be modal)?

If you need additional information please comment, I'll extend the question, but right now I don't know what to show besides the code already linked at the beginning.

Upvotes: 1

Views: 927

Answers (2)

Mike Nakis
Mike Nakis

Reputation: 62045

This is all the gimmicks I had to do in order to get this to work without having to use async/await:

using SysThread = System.Threading;
using WpfThread = System.Windows.Threading;
using SysTasks = System.Threading.Tasks;
using MahCtl = MahApps.Metro.Controls;
using MahDlg = MahApps.Metro.Controls.Dialogs;
using Wpf = System.Windows;
.
.
.
private SysThread.CancellationTokenSource tokenSource;
.
.
.
    MahCtl.MetroWindow parentMetroWindow = Wpf.Application.Current.Windows.OfType<MahCtl.MetroWindow>().First();
    var metroDialogSettings = new MahDlg.MetroDialogSettings();
    metroDialogSettings.OwnerCanCloseWithDialog = true; //does not appear to have any effect
    metroDialogSettings.AnimateHide             = false;
    metroDialogSettings.AnimateShow             = false;
    using( tokenSource = new SysThread.CancellationTokenSource() )
    {
        metroDialogSettings.CancellationToken = tokenSource.Token;
        SysTasks.Task<MahDlg.MessageDialogResult> task = MahDlg.DialogManager.ShowMessageAsync( parentMetroWindow, title, message, mahStyle, metroDialogSettings );
        parentMetroWindow.Closing += onMainWindowClosing;
        while( !(task.IsCompleted || task.IsCanceled || task.IsFaulted) )
            Wpf.Application.Current.Dispatcher.Invoke( WpfThread.DispatcherPriority.Background, new Action( delegate { } ) );
        parentMetroWindow.Closing -= onMainWindowClosing;
        return task.Result;
    }
.
.
.
private void onMainWindowClosing( object sender, SysCompMod.CancelEventArgs cancelEventArgs )
{
    tokenSource.Cancel();
}

The extra handler for the Closing event of the main window is necessary in order to handle the situation where the user attempts to close the main window of your application via the task bar, and while a modal dialog box is open, because OwnerCanCloseWithDialog does not seem to have any effect, or it was never meant to do what the documentation tricked me into believing that it was perhaps meant to do.

Upvotes: 0

Joel Lucsy
Joel Lucsy

Reputation: 8706

You mention task.Wait(). If you started a task to show the dialog, I'm afraid you can't do that. The GUI is single threaded. You can still await the result, just has to be initiated from the main thread, not a task.

Upvotes: 1

Related Questions