Fabio
Fabio

Reputation: 32463

Show MessageBox in Winforms with MVVM pattern

How to call MessageBox.Show() based on the result of ViewModel method?

ViewModel

Public Class PersonViewModel
    Inherits ViewModels.ViewModelBase 'basic INotifyPropertyChanged staff

    Private _Model As Person
    Public Property FirstName As String
    Public Property LastName As String

    'BasicSub is class implemented ICommand taking Execute method as parameter
    Public Property SaveCommand As New Commands.BasicSub(AddressOf Me.SaveModel)

    Private Sub SaveModel()
        If _Model.Save() = False Then
            'Here inform View about saving wasn't successful
        End If
    End Sub
End Class

View

Public Class PersonView 
    Inherits Form

    'I use BindingSource for bindings
    Private BindingSourceViewModel As BindingSource

    Public Sub New(viewmodel As Object)
        Me.InitializeComponents()

        Me.BindingSourceViewModel.DataSource = viewmodel
    End Public

End Class

View have a button which Click event bounded to the Command property

I understand MVVM as simple separating of concerns.
View (In Winforms this is Form) have only own logic. Doesn't matter designer code or codebehind.
ViewModel know about Model but didn't know about View.

Now I am little bid stack about how MessageBox can be called based on the result of Save Command/Method while keeping View and ViewModel separeted?
Because MessageBox.Show is obviously a part of the View

At this moment i use workaround which on my opinion breaking MVVM pattern.
MessageBox.Show executed from ViewModel inside SaveModel() method if _Model.Save returns false

I have checked answer WPF MessageBox with MVVM pattern?, but at this moment wasn't influenced by using some intermediate types. I trying to keep Views and ViewModels in the different project, and Views haven't any references to other application libraries excepts resources

@HighCore, I know difference between Winforms and WPF :)

Upvotes: 0

Views: 945

Answers (1)

DmitryG
DmitryG

Reputation: 17848

As a visual element, any message box is in fact, part of a View. Thus, if you show your message box directly from a ViewModel (define a command that calls the MessageBox.Show() method), this simple code will break the main MVVM concept - ViewModels must not refer to Views - and make it impossible to write unit-tests for your ViewModel. To get around this difficulty, the you can use services concepts. A service is a kind of IOC concept that removes any references between a ViewModel and View layers. In code, a service is an interface used within the ViewModel code without any assumption of "when" and "how" this interface is implemented:

Public Class PersonViewModel
    Protected ReadOnly Property MessageBoxService() As IMessageBoxService
        Get 
            Return Me.GetService(Of IMessageBoxService)()
        End Get 
    End Property
    Public Sub Save()
        If Not _Model.Save() Then
            MessageBoxService.Show("Something wrong!")            
        End If
    End Sub 
End Class

You can provide you View Model with IMessageBoxService implementation using DI/IoC.

P.S. If you're using DevExpress WinForms controls you can extend your MVVM app with cool things like POCO-ViewModels, bindings&commanding, services, messenger and etc. - all the fully adapted for WinForms environment.

Upvotes: 3

Related Questions