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

后端 未结 12 1305
清歌不尽
清歌不尽 2020-11-28 05:55

I\'ve got a WPF application which calls MessageBox.Show() way back in the ViewModel (to check if the user really wants to delete). This actually works

相关标签:
12条回答
  • 2020-11-28 06:29

    Services to the rescue. Using Onyx (disclaimer, I'm the author) this is as easy as:

    public void Foo()
    {
        IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
        dm.Show("Hello, world!");
    }
    

    In a running application, this will indirectly call MessageBox.Show("Hello, world!"). When testing, the IDisplayMessage service can be mocked and provided to the ViewModel to do what ever you want to accomplish during the test.

    0 讨论(0)
  • 2020-11-28 06:34

    There is so many answers on this topic that vary from creating a custom class to using third party libraries. I would say use a third party library if you want cool pop ups with nice visuals.

    But if you just want to use the regular message box from microsoft for your WPF app here is an MVVM/unit test friendly implementation:

    Initially I thought I would just inherit from message box and wrap it with an interface but I couldn't due to Message box not having a public constructor, so here is the "easy" solution:

    Decompiling Message box in visual studio you can see all the method overloads, I checked which ones I wanted then created a new class and added the methods, wrapped it with an interface and ta-da! Now you can use ninject to bind the interface and class, inject it and use Moq to unit test e.t.c.

    Create an interface (only added a few of the overloads as I don't need them all):

    public interface IMessageBox
        {
            /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>          
            MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);
    
            /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>           
            MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
    
            /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
            MessageBoxResult Show(string messageBoxText, string caption);
        }
    

    Then we have the class that will inherit from it:

    public class MessageBoxHelper : IMessageBox
        {
            /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>            
            public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button,
                MessageBoxImage icon)
            {
                return MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.None,
                    MessageBoxOptions.None);
            }
    
            /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>            
            public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
            {
                return MessageBox.Show(messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None,
                    MessageBoxOptions.None);
            }
    
            /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
            public MessageBoxResult Show(string messageBoxText, string caption)
            {
                return MessageBox.Show(messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None,
                    MessageBoxResult.None, MessageBoxOptions.None);
            }
    
            /// <summary>Displays a message box that has a message and that returns a result.</summary>           
            public MessageBoxResult Show(string messageBoxText)
            {
                return MessageBox.Show(messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None,
                    MessageBoxResult.None, MessageBoxOptions.None);
            }
        }
    

    Now just use this when injecting e.t.c and boom u have a flimsy abstraction that will do the trick... which is fine depending on where you will use it. My case is a simple app only meant to do a few things, so no point over engineering a solution. Hope this helps someone.

    0 讨论(0)
  • 2020-11-28 06:34

    I would just throw it from the VM. I dont want to have to use someone else's service or write my own just to throw a messagebox.

    0 讨论(0)
  • 2020-11-28 06:35

    What about raising an Event like "MessageBoxRequested" handled in the codebehind of the View (anyway it's View only code so I don't see any problem with having this code on the codebehind).

    0 讨论(0)
  • 2020-11-28 06:37

    Just in case anyone else is still reading and unsatisfied:

    I just wanted to handle 'notification' type MessageBoxes (i.e. I don't care about the DialogResult), but the problem that I have with most solutions I've read about is that they seem to indirectly force you to choose your View implementation (that is, currently I have a MessageBox.Show, but if I later decide to just fiddle with the visibility of a hidden panel directly in my View, that won't mesh very nicely with an INotification interface passed in to the ViewModel).

    So I went for quick and dirty:

    The ViewModel has a string NotificationMessage property, with changes notified to PropertyChanged.

    The View subscribes to PropertyChanged, and if it sees the NotificationMessage property come through, does whatever it wants.

    OK, so this means the View has code-behind, and the name of PropertyChanged is hard-coded, but it would be hard-coded in the XAML anyway. And it means I avoid all the stuff like converters for Visibility, and properties to say whether the notification is still visible or not.

    (Admittedly this is just for a limited use-case (fire and forget), I haven't given much thought to how I might want to extend it.)

    0 讨论(0)
  • 2020-11-28 06:37

    I've implemented a Behavior that listens to a Message from the ViewModel. It's based on Laurent Bugnion solution, but since it doesn't use code behind and is more reusable, I think it's more elegant.

    Check it out here

    Cache of the broken link

    0 讨论(0)
提交回复
热议问题