简体   繁体   中英

Wait for MahApps Metro Dialog to return result

I have a ViewModel sending a message (using MVVM Light Messenger) to the View to show a Metro Dialog as follows:

In ViewModel, I call this code from the DialogBox class:

DialogBox.ShowDialogBox(
                        (result) => { DialogResult(result); },
                        "Dialog Title",
                        "Dialog Message",
                        MessageDialogStyle.AffirmativeAndNegative
                        );

This is the DialogBox Class which deals with sending the message to the View:

public class DialogBox
{
    public Action<MessageDialogResult> dialogResultCallBack { get; set; }
    public string dialogTitle;
    public string dialogText;
    public MessageDialogStyle dialogStyle;
    public string okButtonText;
    public string cancelButtonText;

    public DialogBox(Action<MessageDialogResult> _dialogResultCallBack, string _dialogTitle, string _dialogText, MessageDialogStyle _dialogStyle, string _okButtonText, string _cancelButtonText)
    {
        dialogResultCallBack = _dialogResultCallBack;
        dialogTitle = _dialogTitle;
        dialogText = _dialogText;
        dialogStyle = _dialogStyle;
        okButtonText = _okButtonText;
        cancelButtonText = _cancelButtonText;
    }


    public static void ShowDialogBox(Action<MessageDialogResult> _dialogResultCallBack, string _dialogTitle, string _dialogText,
        MessageDialogStyle _dialogStyle, string _affirmativeButtonText = "OK", string _negativeButtonText = "Cancel")
    {
        Messenger.Default.Send(new DialogBox(
                       _dialogResultCallBack,
                       _dialogTitle,
                       _dialogText,
                       _dialogStyle,
                       _affirmativeButtonText,
                       _negativeButtonText), GlobalResources.MessengerTokens.dialogTokenMainWindow);
    }
}

The View codebehind has the following code to receive the message:

Messenger.Default.Register<DialogBox>(this, GlobalResources.MessengerTokens.dialogTokenMainWindow, dialogData =>
            {
                ShowMessageDialog(dialogData);
            });

And the ShowMessageDialog deals with showing the actual dialog. These all work fine.

Currently, when the user has selected either Affirmative/Negative, the result is returned and triggers an action call to DialogResult(result) in the ViewModel as seen in the topmost code snippet.

private void DialogResult(MessageDialogResult result)
    {
        if (result == MessageDialogResult.Affirmative)
        {
             //deal with the situation
        }
        else
        {
            //deal with the situation
        }
    }

I would actually like to wait for the result straight away after calling the DialogBox.ShowDialogBox() method in the ViewModel. The current approach is causing the code to jump to a separate method call rather than being able to deal with the result straight away. To illustrate this briefly,

if(condition)
{
  DialogBox.ShowDialogBox(...);

  //Needs some sort of await method to wait for results here

  if(result == MessageDialogResult.Affirmative)
  {
         //do stuff
  }
  else
  {
        //do stuff
  }
 }

I have seen some sample code at least on WinForms that waiting for a result is easier (using codebehind and without MVVM) by doing something like:

if (MessageBox.Show("Title", "Message", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.OK)

Could there be a similar approach I could take for my current situation? Thanks for any suggestions and sorry if my question was too long.

I think there is a better way of doing what you are doing. To make this more MVVM, this is what I do... Firstly, I use Caliburn Micro to handle my MVVM stuff and MEF. So first we have two interfaces:

internal interface IDialogViewModel
{
    event EventHandler Closed;
}

and the following interface will help you get results for your dialog

public interface IDialogManager
{
    /// <summary>
    /// Show a dialog that performs as Task with generic return type. 
    /// </summary>
    /// <typeparam name="TResult">The result to be returned from the dialog task.</typeparam>
    /// <param name="viewModel">The DialogViewModel type to be displayed.</param>
    /// <returns>The Task to be awaited.</returns>
    Task<TResult> ShowDialog<TResult>(DialogViewModel<TResult> viewModel);

    /// <summary>
    /// Show a dialog that performs as Task.
    /// </summary>
    /// <param name="viewModel">The result to be returned from the dialog task.</param>
    /// <returns>The Task to be awaited.</returns>
    Task ShowDialog(DialogViewModel viewModel);
}

The implementation of these interfaces are

/// <summary>
/// DialogViewModel class which should be inherited for all view 
/// model that want to be displayed as metro dialogs.
/// </summary>
public abstract class DialogViewModel : Screen, IDialogViewModel
{
    private readonly TaskCompletionSource<int> tcs;
    internal Task Task { get { return tcs.Task; } }

    /// <summary>
    /// Deafult constructor.
    /// </summary>
    protected DialogViewModel()
    {
        tcs = new TaskCompletionSource<int>();
    }

    /// <summary>
    /// Close the dialog.
    /// </summary>
    protected void Close()
    {
        tcs.SetResult(0);
        var handler = Closed;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    /// <summary>
    /// Closed event.
    /// </summary>
    public event EventHandler Closed;
}

/// <summary>
/// DialogViewModel class which should be inherited for all view 
/// model that want to be displayed as metro dialogs that can return a 
/// specific result.
/// </summary>
public abstract class DialogViewModel<TResult> : Screen, IDialogViewModel
{
    private readonly TaskCompletionSource<TResult> tcs;
    internal Task<TResult> Task { get { return tcs.Task; } }

    /// <summary>
    /// Deafult constructor.
    /// </summary>
    protected DialogViewModel()
    {
        tcs = new TaskCompletionSource<TResult>();
    }

    /// <summary>
    /// Close the dialog.
    /// </summary>
    protected void Close(TResult result)
    {
        tcs.SetResult(result);
        var handler = Closed;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    /// <summary>
    /// Closed event.
    /// </summary>
    public event EventHandler Closed;
}

and the manager class is

/// <summary>
/// The DialogManager that can be used to show Views as Metro modal dialogs.
/// Import IDialogManager to any view model that needs to show a metro message 
/// box.
/// </summary>
[Export(typeof(IDialogManager))]
public class DialogManager : IDialogManager
{
    /// <summary>
    /// Show the required dialog.
    /// </summary>
    /// <param name="viewModel">The view model ascociated with the view.</param>
    public async Task ShowDialog(DialogViewModel viewModel)
    {
        // Locate the ascociated view.
        var viewType = ViewLocator.LocateTypeForModelType(viewModel.GetType(), null, null);
        var dialog = (BaseMetroDialog)Activator.CreateInstance(viewType);
        if (dialog == null)
        {
            throw new InvalidOperationException(
                String.Format("The view {0} belonging to view model {1} " +
                                  "does not inherit from {2}",
                                  viewType,
                                  viewModel.GetType(),
                                  typeof(BaseMetroDialog)));
        }
        dialog.DataContext = viewModel;

        // Show the metro window.
        MetroWindow firstMetroWindow = 
            Application.Current.Windows.OfType<MetroWindow>().First();
        await firstMetroWindow.ShowMetroDialogAsync(dialog);
        await viewModel.Task;
        await firstMetroWindow.HideMetroDialogAsync(dialog);
    }

    /// <summary>
    /// Show the required dialog.
    /// </summary>
    /// <typeparam name="TResult">The type of result to return.</typeparam>
    /// <param name="viewModel">The view model ascociated with the view.</param>
    public async Task<TResult> ShowDialog<TResult>(DialogViewModel<TResult> viewModel)
    {
        // Locate the ascociated view.
        var viewType = ViewLocator.LocateTypeForModelType(viewModel.GetType(), null, null);
        var dialog = (BaseMetroDialog)Activator.CreateInstance(viewType);
        if (dialog == null)
        {
            throw new InvalidOperationException(
                String.Format("The view {0} belonging to view model {1} " +
                                  "does not inherit from {2}",
                                  viewType,
                                  viewModel.GetType(),
                                  typeof(BaseMetroDialog)));
        }
        dialog.DataContext = viewModel;

        // Show the metro window.
        MetroWindow firstMetroWindow = Application.Current.Windows.OfType<MetroWindow>().First();
        await firstMetroWindow.ShowMetroDialogAsync(dialog);
        TResult result = await viewModel.Task;
        await firstMetroWindow.HideMetroDialogAsync(dialog);
        return result;
    }
}

We also have the message box settings

/// <summary>
/// Class that holds the settings for message box dialogs.
/// </summary>
public class MessageBoxSettings
{
    /// <summary>
    /// Default constructor.
    /// </summary>
    public MessageBoxSettings()
    {
        this.AffirmativeButtonText = "OK";
        this.NegativeButtonText = "Cancel";
        this.MessageDialogStyle = MessageDialogStyle.AffirmativeAndNegative;
        this.MetroColorDialogScheme = MetroDialogColorScheme.Theme;
        this.Animation = false;
    }

    /// <summary>
    /// Sets the button styles to use.
    /// Default is 'OK' and 'Cancel'.
    /// </summary>
    public MessageDialogStyle MessageDialogStyle { get; set; }

    /// <summary>
    /// The color sheme to use for the dialog.
    /// </summary>
    public MetroDialogColorScheme MetroColorDialogScheme { get; set; }

    /// <summary>
    /// Affirmative button text. Default OK.
    /// </summary>
    public string AffirmativeButtonText { get; set; }

    /// <summary>
    /// The negative button text to use.
    /// </summary>
    public string NegativeButtonText { get; set; }

    /// <summary>
    /// First auxillary button text.
    /// </summary>
    public string FirstAuxillaryButtonText { get; set; }

    /// <summary>
    /// Second auxillary button text.
    /// </summary>
    public string SecondAuxiliaryButtonText { get; set; }

    /// <summary>
    /// Show animation on the dialog.
    /// </summary>
    public bool Animation { get; set; }
}

Now the view and view model that actually use the code above are

/// <summary>
/// View model for the message box view.
/// </summary>
public class MessageBoxViewModel : DialogViewModel<MessageDialogResult>
{
    private MessageBoxSettings settings;

    #region Initialisation.
    /// <summary>
    /// Null.
    /// </summary>
    public MessageBoxViewModel() { }

    /// <summary>
    /// Default constructor.
    /// </summary>
    /// <param name="title">The title of the message box dialog.</param>
    /// <param name="message">The message to display in the message box.</param>
    public MessageBoxViewModel(string title, string message)
    {
        this.Title = title;
        this.DialogBody = message;
        if (this.settings == null)
            this.settings = new MessageBoxSettings();
        SetDialogVisuals();
    }

    /// <summary>
    /// Overloaded.
    /// </summary>
    /// <param name="title">The title of the message box dialog.</param>
    /// <param name="message">The message to display in the message box.</param>
    /// <param name="settings">MessageBoxSettings for the dialog.</param>
    public MessageBoxViewModel(string title, string message, MessageBoxSettings settings)
    {
        this.Title = title;
        this.DialogBody = message;
        this.settings = settings;
        SetDialogVisuals();
    }
    #endregion // Initialisation.

    #region Class Methods.
    /// <summary>
    /// Set the dialog visuals based on the MessageBoxSettings.
    /// </summary>
    private void SetDialogVisuals()
    {
        // Set dialog button visibility.
        switch (settings.MessageDialogStyle)
        {
            case MessageDialogStyle.Affirmative:
                this.AffirmativeButtonVisibility = Visibility.Visible;
                this.NegativeButtonVisibility = Visibility.Collapsed;
                this.FirstAuxillaryButtonVisibility = Visibility.Collapsed;
                this.SecondAuxillaryButtonVisibility = Visibility.Collapsed;
                break;
            case MessageDialogStyle.AffirmativeAndNegative:
                this.AffirmativeButtonVisibility = Visibility.Visible;
                this.NegativeButtonVisibility = Visibility.Visible;
                this.FirstAuxillaryButtonVisibility = Visibility.Collapsed;
                this.SecondAuxillaryButtonVisibility = Visibility.Collapsed;
                break;
            case MessageDialogStyle.AffirmativeAndNegativeAndDoubleAuxiliary:
                this.AffirmativeButtonVisibility = Visibility.Visible;
                this.NegativeButtonVisibility = Visibility.Visible;
                this.FirstAuxillaryButtonVisibility = Visibility.Visible;
                this.SecondAuxillaryButtonVisibility = Visibility.Visible;
                break;
            case MessageDialogStyle.AffirmativeAndNegativeAndSingleAuxiliary:
                this.AffirmativeButtonVisibility = Visibility.Visible;
                this.NegativeButtonVisibility = Visibility.Visible;
                this.FirstAuxillaryButtonVisibility = Visibility.Visible;
                this.SecondAuxillaryButtonVisibility = Visibility.Collapsed;
                break;
            default:
                break;
        }

        // Set the button text.
        this.AffirmativeButtonText = settings.AffirmativeButtonText;
        this.NegativeButtonText = settings.NegativeButtonText;
        this.FirstAuxillaryButtonText = settings.FirstAuxillaryButtonText;
        this.SecondAuxiliaryButtonText = settings.SecondAuxiliaryButtonText;

        // Color scheme.
        string name = MahApps.Metro.ThemeManager.DetectAppStyle(Application.Current).Item2.Name;
        this.Background = settings.MetroColorDialogScheme == MetroDialogColorScheme.Theme ?
            MahApps.Metro.ThemeManager.Accents
                .Where(a => a.Name.CompareNoCase(name))
                .First().Resources["HighlightBrush"] as SolidColorBrush :
            new SolidColorBrush(System.Windows.Media.Colors.White);
    }

    /// <summary>
    /// Handles the button click events for the affermative button.
    /// </summary>
    public void AffirmativeButtonClick()
    {
        Close(MessageDialogResult.Affirmative);
    }

    /// <summary>
    /// Handles the button click events for the negative button.
    /// </summary>
    public void NegativeButtonClick()
    {
        Close(MessageDialogResult.Negative);
    }

    /// <summary>
    /// Handles the button click events for the first auxillary button.
    /// </summary>
    public void FirstAuxillaryButtonClick()
    {
        Close(MessageDialogResult.FirstAuxiliary);
    }

    /// <summary>
    /// Handles the button click events for the second auxillary button.
    /// </summary>
    public void SecondAuxillaryButtonClick()
    {
        Close(MessageDialogResult.SecondAuxiliary);
    }
    #endregion // Class Methods.

    #region Properties.
    /// <summary>
    /// Hold the dialog title.
    /// </summary>
    private string title;
    public string Title
    {
        get { return title; }
        set
        {
            if (title == value)
                return;
            title = value;
            NotifyOfPropertyChange(() => Title);
        }
    }

    /// <summary>
    /// Hold the text for the dialog body.
    /// </summary>
    private string dialogBody;
    public string DialogBody
    {
        get { return dialogBody; }
        set
        {
            if (dialogBody == value)
                return;
            dialogBody = value;
            NotifyOfPropertyChange(() => DialogBody);
        }
    }

    /// <summary>
    /// Sets the button styles to use.
    /// Default is 'OK' and 'Cancel'.
    /// </summary>
    private MessageDialogStyle messageDialogStyle =
        MessageDialogStyle.AffirmativeAndNegative;
    public MessageDialogStyle MessageDialogStyle
    {
        get { return messageDialogStyle; }
        set
        {
            if (messageDialogStyle == value)
                return;
            messageDialogStyle = value;
            NotifyOfPropertyChange(() => MessageDialogStyle);
        }
    }

    /// <summary>
    /// The color sheme to use for the dialog.
    /// </summary>
    private SolidColorBrush background;
    public SolidColorBrush Background
    {
        get { return background; }
        set
        {
            if (background == value)
                return;
            background = value;
            NotifyOfPropertyChange(() => Background);
        }
    }

    /// <summary>
    /// Affirmative button text. Default OK.
    /// </summary>
    private string affirmativeButtonText = "OK";
    public string AffirmativeButtonText
    {
        get { return affirmativeButtonText; }
        set
        {
            if (affirmativeButtonText == value)
                return;
            affirmativeButtonText = value;
            NotifyOfPropertyChange(() => AffirmativeButtonText);
        }
    }

    /// <summary>
    /// Visibility for the default affirmative button.
    /// </summary>
    private Visibility affirmativeButtonVisibility = Visibility.Visible;
    public Visibility AffirmativeButtonVisibility
    {
        get { return affirmativeButtonVisibility = Visibility.Visible; }
        set
        {
            if (affirmativeButtonVisibility == value)
                return;
            affirmativeButtonVisibility = value;
            NotifyOfPropertyChange(() => AffirmativeButtonVisibility);
        }
    }

    /// <summary>
    /// The negative button text to use.
    /// </summary>
    private string negativeButtonText = "Cancel";
    public string NegativeButtonText
    {
        get { return negativeButtonText; }
        set
        {
            if (negativeButtonText == value)
                return;
            negativeButtonText = value;
            NotifyOfPropertyChange(() => NegativeButtonText);
        }
    }

    /// <summary>
    /// Visibility for the default negative button.
    /// </summary>
    private Visibility negativeButtonVisibility = Visibility.Visible;
    public Visibility NegativeButtonVisibility
    {
        get { return negativeButtonVisibility; }
        set
        {
            if (negativeButtonVisibility == value)
                return;
            negativeButtonVisibility = value;
            NotifyOfPropertyChange(() => NegativeButtonVisibility);
        }
    }

    /// <summary>
    /// First auxillary button text.
    /// </summary>
    private string firstAuxillaryButtonText;
    public string FirstAuxillaryButtonText
    {
        get { return firstAuxillaryButtonText; }
        set
        {
            if (firstAuxillaryButtonText == value)
                return;
            firstAuxillaryButtonText = value;
            NotifyOfPropertyChange(() => FirstAuxillaryButtonText);
        }
    }

    /// <summary>
    /// First auxillary button visibility.
    /// </summary>
    private Visibility firstAuxillaryButtonVisibility = Visibility.Collapsed;
    public Visibility FirstAuxillaryButtonVisibility
    {
        get { return firstAuxillaryButtonVisibility; }
        set
        {
            if (firstAuxillaryButtonVisibility == value)
                return;
            firstAuxillaryButtonVisibility = value;
            NotifyOfPropertyChange(() => FirstAuxillaryButtonVisibility);
        }
    }

    /// <summary>
    /// Second auxillary button text.
    /// </summary>
    private string secondAuxiliaryButtonText;
    public string SecondAuxiliaryButtonText
    {
        get { return secondAuxiliaryButtonText; }
        set
        {
            if (secondAuxiliaryButtonText == value)
                return;
            secondAuxiliaryButtonText = value;
            NotifyOfPropertyChange(() => SecondAuxiliaryButtonText);
        }
    }

    /// <summary>
    /// Second auxillary button visibility.
    /// </summary>
    private Visibility secondAuxillaryButtonVisibility = Visibility.Collapsed;
    public Visibility SecondAuxillaryButtonVisibility
    {
        get { return secondAuxillaryButtonVisibility; }
        set
        {
            if (secondAuxillaryButtonVisibility == value)
                return;
            secondAuxillaryButtonVisibility = value;
            NotifyOfPropertyChange(() => SecondAuxillaryButtonVisibility);
        }
    }
    #endregion // Properties.
}

The view is

<MahAppsDialogs:CustomDialog 
        x:Class="GambitFramework.Core.MessageBox.MessageBoxView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Caliburn="http://www.caliburnproject.org"
        xmlns:MahApps="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:Local="clr-namespace:GambitFramework.Core.MessageBox"
        xmlns:Converters="clr-namespace:GambitFramework.Core.Converters;assembly=GambitFramework"
        xmlns:MahAppsDialogs="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
        Title="{Binding Title}">
    <MahAppsDialogs:CustomDialog.Content>
        <TextBlock Text="{Binding DialogBody}"
                      Margin="0,5,0,0"
                      TextWrapping="Wrap"/>
    </MahAppsDialogs:CustomDialog.Content>
    <MahAppsDialogs:CustomDialog.DialogBottom>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25*" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="25*" />
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="1"
                            Orientation="Horizontal" 
                            HorizontalAlignment="Right"
                            Margin="0,0,0,0">
                <Button x:Name="AffirmativeButton" 
                          Content="{Binding AffirmativeButtonText}"
                          Visibility="{Binding AffirmativeButtonVisibility}"
                          Style="{StaticResource AccentedSquareButtonStyle}"
                          Caliburn:Message.Attach="[Event Click] = [Action AffirmativeButtonClick()]"
                          MinWidth="75"
                          Padding="15,0"
                          Margin="5,10,0,5"/>
                <Button x:Name="NegativeButton" 
                          Content="{Binding NegativeButtonText}"
                          Visibility="{Binding NegativeButtonVisibility}" 
                          Caliburn:Message.Attach="[Event Click] = [Action NegativeButtonClick()]"
                          MinWidth="75"
                          Padding="15,0"
                          Margin="10,10,0,5"/>
                <Button x:Name="FirstAuxiliaryButton" 
                          Content="{Binding FirstAuxillaryButtonText}"
                          Visibility="{Binding FirstAuxillaryButtonVisibility}"
                          Caliburn:Message.Attach="[Event Click] = [Action FirstAuxillaryButtonClick()]"
                          MinWidth="75"
                          Padding="15,0"
                          Margin="5,10,0,5"/>
                <Button x:Name="SecondAuxiliaryButton" 
                          Content="{Binding SecondAuxiliaryButtonText}"
                          Visibility="{Binding SecondAuxillaryButtonVisibility}"
                          Caliburn:Message.Attach="[Event Click] = [Action SecondAuxillaryButtonClick()]"
                          MinWidth="75"
                          Padding="15,0"
                          Margin="5,10,0,5"/>
            </StackPanel>
        </Grid>
    </MahAppsDialogs:CustomDialog.DialogBottom>
</MahAppsDialogs:CustomDialog>

This view has an empty code behind. This code can then be used as follows

MessageBoxSettings settings = new MessageBoxSettings()
{
    MessageDialogStyle = MessageDialogStyle.AffirmativeAndNegative,
    MetroColorDialogScheme = MetroDialogColorScheme.Accented,
    AffirmativeButtonText = "Delete",
    NegativeButtonText = "Cancel"
};
string message = String.Format(
    "Are you sure you want to delete back test \"{0}\" {1}",
    SelectedBackTest.Name,
    SelectedBackTest.LastRun == null ? 
        String.Empty : 
        String.Format("which was late run on {0:G}?", SelectedBackTest.LastRun));
MessageDialogResult r = await dialogManager
    .ShowDialog<MessageDialogResult>(
        new MessageBoxViewModel("Confirm Delete", message, settings));
if (r == MessageDialogResult.Affirmative)
{
    ...
}

I hope this helps.

The accepted answer requires some extra library AND a ridiculous amount of code. Here is what I did to wait for the dialog to complete, using MahApps only.

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 Win32 = Microsoft.Win32;
using Wpf = System.Windows;
using SysCompMod = System.ComponentModel;
        [...]
        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( SysThread.CancellationTokenSource tokenSource = new SysThread.CancellationTokenSource() )
        {
            metroDialogSettings.CancellationToken = tokenSource.Token;
            SysTasks.Task<MahDlg.MessageDialogResult> task = MahDlg.DialogManager.ShowMessageAsync( parentMetroWindow, title, message, mahStyle, metroDialogSettings );
            // ReSharper disable once AccessToDisposedClosure
            SysCompMod.CancelEventHandler cancelEventHandler = (s, e) => tokenSource.Cancel();
            parentMetroWindow.Closing += cancelEventHandler;
            while( !(task.IsCompleted || task.IsCanceled || task.IsFaulted) )
                Wpf.Application.Current.Dispatcher.Invoke( WpfThread.DispatcherPriority.Background, new Action( delegate { } ) );
            parentMetroWindow.Closing -= cancelEventHandler;
            return responseFromMahAppsMessageDialogResult( type, task.Result );
        }

The cancelEventHandler is necessary in case the user attempts to close your main window via the taskbar while the modal dialog is up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM