Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MahApps MessageBoxes using MVVM

Simple question for the MahApps Merry Men. I have implemented an application using your great metro styled controls using Caliburn.Micro for the MVVM stuff. The new message dialogs look great, but currently there is not clear way of launching these dialogs with out writing my own wrapper (which I am not against). However, has this been done or is there something I missing so that I can invoke a message box from a view model without any fuss?

Thanks for your time.

like image 932
MoonKnight Avatar asked Feb 27 '14 23:02

MoonKnight


2 Answers

As of 1.1.3-ALPHA* (to become 1.2.0) MahApps provides a helper to launch dialogs from a VM, which works in a multiple Window setup:

1) Use an attached property in your Window to register your view model with the dialog sub-system.

Assuming your View’s DataContext is set to the view model from where you want to launch the dialog, add these attributes:

<Controls:MetroWindow 
    xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
    Dialog:DialogParticipation.Register="{Binding}">

2) Grab/inject DialogCoordinator:

new MainWindowViewModel(DialogCoordinator.Instance);

3) Show your dialog from the view model. Use "this" as the context so MahApps can marry your view model to the correct window:

_dialogCoordinator.ShowMessageAsync(this, "Message from VM", "MVVM based dialogs!")
like image 147
James Willock Avatar answered Oct 12 '22 12:10

James Willock


I have created a wrapper to call the MahApps.Metro message dialog, cause I was having the same problem with my MVVM project. I had to create a list of opened windows, which the first window will always be my MainWindow.

Here's my DialogService code:

public async Task<MessageDialogResult> ShowMessage(string message, MessageDialogStyle dialogStyle)
{
    var metroWindow = (_openedViews.First() as MetroWindow);
    metroWindow.MetroDialogOptions.ColorScheme = MetroDialogColorScheme.Accented;

    return await metroWindow.ShowMessageAsync("MY TITLE", message, dialogStyle, metroWindow.MetroDialogOptions);
}

This code can be used to show dialogs with or without a result. You can notice that its return is a Task<MessageDialogResult>, so if you want to get the result, you can do just like that on your ViewModel:

MessageDialogResult result = await _dialog.ShowMessage("SOME MESSAGE HERE", MessageDialogStyle.AffirmativeAndNegative).ConfigureAwait(false);

if (result == MessageDialogResult.Affirmative)
{
    //Do something
}

By the way, if the method that calls the ShowMessage() needs a result, you MUST put async on the assignment, otherwise it won't work. (if you only want to show a message dialog, it's not necessary).

My project is using Framework 4.0, and I can only use async/await due to the package I had to install from NuGet. You can acces this link for the MSDN documentation of this package, and you can download the package here.

I hope it has solved your problem.

EDIT:

I have implemented a method on my DialogService to open any windows from any ViewModel. This method uses Microsoft Unity framework to instantiate my object, and then I call Show() to open itself. Before a call Show(), I add this window on a list.

See my code:

public void ShowView<T>(params ParameterOverride[] parameter)
{
    var window = UnityServiceConfigurator.Instance.Container.Resolve<T>(parameter) as MetroWindow;

    if (window != null)
    {
        if (Application.Current.MainWindow != window)
        {
            window.Owner = Application.Current.MainWindow;
            var ownerMetroWindow = (window.Owner as MetroWindow);

            if (!ownerMetroWindow.IsOverlayVisible())
                ownerMetroWindow.ShowOverlayAsync();
        }

        if (!_openedViews.Contains(window))
            _openedViews.Add(window);

        window.Show();
    }
}

This is how I call from my ViewModel:

_dialog.ShowView<MyView>();

If you have only one window on your entire software, you can save its reference and use it to show the ShowMessageAsync() without needing to create a List only to use the First. Like this:

var metroWindow = (Application.Current.MainWindow as MetroWindow);
like image 45
Guilherme Oliveira Avatar answered Oct 12 '22 14:10

Guilherme Oliveira