views:

261

answers:

5

Perhaps I have been doing Flex development with Frameworks like Cairngorm too long but I still don’t get MVVM. I am aware that Cairngorm is a framework and MVVM is a design pattern, but what I am comparing here is Cairngorms implementations of design patterns, mainly the model view controller and the command pattern. Don’t get me wrong, I think the idea of binding a view to a view model is great and the advantages in testability and designer-programmer workflow are great. But there are two things that bother me: one is programming all my actions with Commands, which by the way also bordered me from Cairngorm. Only in Cairngorm the way they implemented the command pattern gave you the benefit of having a centralized controller for all your commands, which you don’t seem to get with MVVM, unless I am missing something. And if I thought implementing the commands in Cairngorm was convoluted in MVVM is much worst, I mean having to create private classes that implement ICommand for everything I do seems like too much. And then you have the problem that not all controls implement commands so for example if you are using a ListBox, which I use a lot, you are out of luck; there are workarounds but all kind of convoluted.

The other thing that bothers me is the communication between View Models. In a standard Model View Controller you collect all you information on a centralized model which is observed by the views, but this doesn’t seem to be the case with MVVM, at least not in the examples that I have seen. So, for example, if you have a control with a list that you use to select an item which is then used as source for different views and consequent actions it is not clear to me how you notify everybody of the changes without a centralized model.

I am aware of MVVMFoundation and the work of Tom Ershamam about WPF Commands Everywhere. Called me old fashioned but I think that in order to really understand a pattern you have to build an application that uses it from scratch. Which is what I am doing, but the whole time I keep thinking I must be missing something essential because I don’t seem to be able to quiet this little voice in my head that keeps telling me there must be a better way.

+3  A: 

Well writing a new command that impelements ICommand seems a bit over kill have a look at this class: VB.NET: Public Class RelayCommand Implements ICommand

#Region " Declarations"
    Private mCanExecute As Predicate(Of Object)
    Private mExecute As Action(Of Object)
#End Region

#Region " Constructors"
    Public Sub New(ByVal canExecute As Predicate(Of Object), ByVal execute As Action(Of Object))
        mCanExecute = canExecute
        mExecute = execute
    End Sub

    Public Sub New(ByVal execute As Action(Of Object))
        mCanExecute = Nothing
        mExecute = execute
    End Sub
#End Region

#Region " Events"
    Public Custom Event CanExecuteChanged As EventHandler Implements System.Windows.Input.ICommand.CanExecuteChanged
        AddHandler(ByVal value As EventHandler)
            AddHandler CommandManager.RequerySuggested, value
        End AddHandler
        RemoveHandler(ByVal value As EventHandler)
            RemoveHandler CommandManager.RequerySuggested, value
        End RemoveHandler
        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            Throw New ApplicationException("Can't raise custom command!")
        End RaiseEvent
    End Event
#End Region

#Region " Public Methods"
    Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
        If (mCanExecute Is Nothing) Then
            Return True
        End If
        Return mCanExecute(parameter)
    End Function

    Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
        mExecute(parameter)
    End Sub
#End Region

End Class

C#

public class RelayCommand : ICommand
{

    #region Declarations
    private Predicate<object> mCanExecute;
    private Action<object> mExecute;
    #endregion

    #region Constructors
    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        mCanExecute = canExecute;
        mExecute = execute;
    }

    public RelayCommand(Action<object> execute)
    {
        mCanExecute = null;
        mExecute = execute;
    }
    #endregion

    #region Events
    public event EventHandler CanExecuteChanged {
        add {
            CommandManager.RequerySuggested += value;
        }
        remove {
            CommandManager.RequerySuggested -= value;
        }
    }
    #endregion

    #region Public Methods
    public bool CanExecute(object parameter)
    {
        if ((mCanExecute == null)) {
            return true;
        }
        return mCanExecute(parameter);
    }

    public void Execute(object parameter)
    {
        mExecute(parameter);
    }
    #endregion

}

and to use it just expose a property of type ICommand that returns a new RelayCommand with delegates to a function...

vb.net

Private mDeleteCommand As ICommand

Public ReadOnly Property DeleteCommand() As ICommand
    Get
        If (mDeleteCommand Is Nothing) Then
            mDeleteCommand = New RelayCommand(AddressOf CanDeleteTodo, AddressOf DeleteTodo)
        End If
        Return mDeleteCommand
    End Get
End Property

C#

private ICommand mDeleteCommand;
public ICommand DeleteCommand {
    get {
        if ((mDeleteCommand == null)) {
            mDeleteCommand = new RelayCommand(CanDeleteTodo, DeleteTodo);
        }
        return mDeleteCommand;
    }
}
Petoj
Thanks a lot, I saw this code on the excellent article by Josh Smith, and is indeed helpful, but it still leaves the question open regarding why we need to use commands always? Are events in code behind inherently evil or is there some circumstances when they are justified?
Julio Garcia
im far from an expert but i try to keep my view code behind empty if i can, so as far as i know you can't databind to an event so that leaves you with commands.. (and i must say to a have a pure XAML view is nice you just have to look in one place)
Petoj
The code behind isn't the ViewModel. The easiest way to get the View to execute code in the ViewModel is to bind a command to the gui object. Event handlers in code behind can call the ViewModel, but if you use binding you cut out the middleman.
Cameron MacFarland
+3  A: 

Whatever the framework/architecture/pattern, you will always need something that responds to a button click, on a toolbar/menu or plain form. And you need something that says if the button/menu should be enabled. So the ICommand interface is nice for this. I agree with Petoj, you don't need a new class. I wrote a simple implementation that takes 1 or 2 delegates, one for the actual response to the click (the Execute method) and an optional one for the "enabled" status of the command. This way, the ViewModel is not cluttered.

But I agree that this is not a centralized repository of commands. But do you really want one ? I prefer to have commands specific to one part of an app to be in the corresponding view model, with appropriate events raised when the rest of the app should be notified.

For the listbox, I bind the SelectedItem property to a property on the ViewModel. With INotifyPropertyChanged, any part of your code can react to the change.

Communication between ViewModels is a good question. If you need different views on the same screen, you can have a "super" view model that contains the view model of each view. There are quite a few MVVM frameworks out there. I used parts of Mark Smith's MVVM helpers, which is quite lightweight and useful.

Timores
A: 

Ok so to give this thread some kind of closure for future reference. First thanks a lot for the answers. The RelayCommand is really a good idea; it really streamlines things a lot and makes thing easy to test and work with. Looks like it is the way to go. Binding to the SelectedItem also seems to solve the problem regarding the lack of command support in ItemsControl. Regarding the communication between ViewModels, I am not convinced that having a super view model solves my problem, since it ties the model to my visual tree. Besides I haven’t found a way in this structure to have a clean, object independent way to communicate between all view models in different hierarchies. So what I am trying out is first creating a centralized model which is a singleton that implements the INotifyPropertyChanged interface. The ViewModels can then have an instance of this model and act on it propagating the corresponding property changes using our good old friend the Observer pattern. Seem to work OK, although I am a little worried of circular references. What do you think?

Julio Garcia
+1  A: 

Helo Julio,

Look like this is an old post, but i really love your question.

Recently i am a flex programmer and a WPF too. I knew Cairngorm (lets Say [C]) framework well, have learnt to use Presentation model using Parsley Framework, and in WPF i realize that Presentation Model has been changed to MVVM pattern.

Command

Command in [C] is diffrent than in MVVM, command in [C] is more satisfied as a Command Pattern, where in [C] controller act as Invoker, so in [C] the command actually can be made to support Chain, Undo, Transaction etc. In MVVM Command is far from Command pattern. The main Idea of using Command in MVVM because ICommand is the only way to doing binding with operation. In Flex you easily bind method to event using click="{viewmodel.doOperation()}" but not in WPF.

Model Locator

It is a bad practice to centralize your application state on a single Model Locator like [C] did. In the other hand you will lost a chance to "easily" unit test your code if you do that. The more dependent your code the harder your test it, if your model locator contains tons of smaller model, than you already put big amount of dependency on your code. AND, the scariest thing using singleton is it is impossible to mock. so if your model locator is non unit-testing friendly than your unit testing process can be full of pain.

actually no best practice used in contex of MVVM for shared model between views like you mention, but you should take a look at dependency injection term to achieve that.

Best Regards

ktutnik
You are right about the testability of a centralized model, but I still think that to share the state of certain global elements between view models a central model is much simpler to develop. It comes to a balance between hard to code (= larger probability of errors) and ease of testing.
Julio Garcia
yes i agree, in some cases it is acceptable, but to programs good quality software sometime we should follow some best practice, you can check it here http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/. The link i provide discussing about singleton but actually mentioned about GLOBAL STATE that was not a best practice on programming. Mark that the author of link i provide is an **Agile Coach** of Google developer.
ktutnik
A: 

People discussing about MVVM have made it appear too theoretical and flex has really different architecture all together that makes MVVM little complicated for people coming from flex.

Let me give you very simple example,

In Flex, mostly we create one MXML for UI Component, and we have our bindable model and we mostly write our code in the events of UI Component as well as non UI Components. For example, WebService, HttpService etc, they are not UI component but they still can be inside the MXML and they can be accessed easily within the MXML code.

So basically you can have, Model + View + Controller in one MXML file organized very easily.

In Silverlight, in XAML, you can only have UI elements as children of page/user control you are modifying. There are limitations, XAML lets you put your non UI element only in resources, and typed variable of the resource you have added is not easily accessible within the code behind of XAML, you have to call find resource to access the code.

To make things easier, MVVM forces you to define different files.

You have one file, that is your model itself, for example Customer.cs

You have another file, that is your ViewModel, which basically is combination of Model + Commands. And you write your Controller code in Command's Executed event.

You have another file, that is your View, view basically binds to all properties of ViewModel which are either Model or Commands.

Akash Kava