26

Possible Duplicate:
How have you successfully implemented MessageBox.Show() functionality in MVVM?

I want to show message box in my MVVM WPF application. so from where to call MessageBox.Show().

Community
  • 1
  • 1
Jeevan Bhatt
  • 5,881
  • 18
  • 54
  • 82
  • 4
    This is heavily downvoted and marked as duplicate, but it's also the top Google result for `mvvm messagebox wpf` ... – Benjol Apr 30 '13 at 09:24
  • 1
    Just saying.. may not be as pretty or whatever, but you could simply just call System.Windows.MessageBox.Show(params); from.. any class. – Para Dec 05 '13 at 15:59
  • 1
    I know it's an old question, but when I did this search, I find a lot of related question, but I did not find a really clear response. So I make my own implementation of a dialogbox/messagebox/popin, and I share it ! http://stackoverflow.com/a/40135791/2546739 – Xav987 Oct 19 '16 at 15:31
  • Here are some helpful links: - https://stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm - https://stackoverflow.com/questions/1098023/how-have-you-successfully-implemented-messagebox-show-functionality-in-mvvm - [WPF MVVM – Simple ‘MessageBox.Show’ With Action & Func](http://www.bjsanca.com/html/developer/wpf/2011/0802/9451.html) by Dean Chalk – Geeth Sep 14 '10 at 04:29
  • if (System.Windows.MessageBox.Show("Are you need to delete?", "", System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.Yes) { // Action } – Rakesh Ravi G Dec 12 '21 at 21:04

2 Answers2

23

In Windows Forms, or WPF without MVVM, you could just say MessageBox.Show() and that was it! Wouldn't it be nice if you could do the same in MVVM?

Here is one way to do this - and it is as close as I can get to MessageBox.Show().

Here is the MVVM friendly MessageBox_Show()!

public class MyViewModel: ViewModelBase
{
    protected void AskTheQuestion()
    {
        MessageBox_Show(ProcessTheAnswer, "Are you sure you want to do this?", "Alert", System.Windows.MessageBoxButton.YesNo);
    }

    public void ProcessTheAnswer(MessageBoxResult result)
    {
        if (result == MessageBoxResult.Yes)
        {
            // Do something
        }
    }
}

Tada!

Here is how it works:

All that MessageBox_Show actually does is fire an event, so it is perfectly MVVM friendly. The ViewModel knows nothing about any view that may or may not be consuming it, and it doesn't perform the showing of a Windows MessageBox on it's own, so it can also be safely unit tested.

To use it in a View, which will cause it to actually show a MessageBox, you just subscribe to the event and call e.Show() in the event handler, like this:

public partial class MyView : UserControl
{
    public MyView()
    {
        InitializeComponent();

        this.DataContext = new MyViewModel();
        (this.DataContext as MyViewModel).MessageBoxRequest += new EventHandler<MvvmMessageBoxEventArgs>(MyView_MessageBoxRequest);
    }

    void MyView_MessageBoxRequest(object sender, MvvmMessageBoxEventArgs e)
    {
        e.Show();
    }
}

And that is all you need to do to show MVVM friendly Windows MessageBoxes.

The code below only needs to be implemented once in your project, or you can put it in a reusable shared library.

Add this to your ViewModel base class so it can be used from any ViewModel:

public class ViewModelBase : INotifyPropertyChanged
{
    //...

    public event EventHandler<MvvmMessageBoxEventArgs> MessageBoxRequest;
    protected void MessageBox_Show(Action<MessageBoxResult> resultAction, string messageBoxText, string caption = "", MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.None, MessageBoxOptions options = MessageBoxOptions.None)
    {
        if (this.MessageBoxRequest != null)
        {
            this.MessageBoxRequest(this, new MvvmMessageBoxEventArgs(resultAction, messageBoxText, caption, button, icon, defaultResult, options));
        }
    }
}

And then add the EventArgs class for the event handler:

public class MvvmMessageBoxEventArgs : EventArgs
{
    public MvvmMessageBoxEventArgs(Action<MessageBoxResult> resultAction, string messageBoxText, string caption = "", MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.None, MessageBoxOptions options = MessageBoxOptions.None)
    {
        this.resultAction = resultAction;
        this.messageBoxText = messageBoxText;
        this.caption = caption;
        this.button = button;
        this.icon = icon;
        this.defaultResult = defaultResult;
        this.options = options;
    }

    Action<MessageBoxResult> resultAction;
    string messageBoxText;
    string caption;
    MessageBoxButton button;
    MessageBoxImage icon;
    MessageBoxResult defaultResult;
    MessageBoxOptions options;

    public void Show(Window owner)
    {
        MessageBoxResult messageBoxResult = MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult, options);
        if (resultAction != null)resultAction(messageBoxResult);
    }

    public void Show()
    {
        MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options);
        if (resultAction != null) resultAction(messageBoxResult);
    }
}

Unit testing is easy:

target.AskTheQuestion();
target.ProcessTheAnswer(System.Windows.MessageBoxResult.Yes);

Happy Coding!

Harlow Burgess
  • 1,876
  • 14
  • 12
  • Good implementation however as it's using Events, this will certainly cause memory leak specially when you have lots of Views. – Hitesh P Sep 16 '16 at 09:33
  • 10
    But by using the references to System.Windows in ViewModelBase for the MessageBoxResult, MessageBoxOptions are you not defeating the purpose of MVVM? – this-Me Jan 04 '17 at 09:41
  • 1
    The goal of MVVM is to separate the UI from the logic, where the ViewModel has no awareness of the View, and where you can easily unit-test the ViewMode. Nowhere it says you can't reference the System.Windows namespace, so I don't see an issue here. As for events, it causes a leak when the event sender (ViewModel) lives longer than the event listener (View). In this case, the ViewModel and View generally have the same longevity so there's no issue here. However, I would move the code out of ViewModelBase into a separate class. – Etienne Charland Jul 02 '18 at 16:51
  • In moving the code into a separate class, you have to make sure you're not using a static event but a class instance initialized within the ViewModel, otherwise THAT would cause a memory leak pinning the Views. – Etienne Charland Jul 02 '18 at 16:55
  • It's a good synchronous implementation, but you will have problems with this on an Async mode, more especially you need to ask a question and wait for the answer from a nonUI thread without deadlock and UI thread errors. For example { var answer= await showMessageAsync()} – Baloo0ch Jan 30 '19 at 18:04
12

I've found that MVVM invokes a streak of OCD in programmers (I know from experience). That's a good thing. But for certain things the effort just isn't worth it, especially if it introduces an entire order of complexity just to ask the user "Are you sure you wish to xxxx?"

My opinion is that MessageBox.Show() may be called from the code-behind, but never the ViewModel. Until dialog boxes integrate better with XAML, just take the hit and don't feel bad about it. It's really a gray area of the current state of WPF UI design.

bufferz
  • 3,400
  • 5
  • 24
  • 37
  • 5
    I am using command so if i will have to show message box after button's can execute and Execute function, i need to pass some data to view's code behind file,Then it will break mvvm. – Jeevan Bhatt Sep 15 '10 at 04:30