Monday 13 December 2010

MVC, MVP & MVVM

MVC, MVVM, MVP

I decided to get to the bottom of these patterns and what the differences are. The most common motivation behind these patterns are the cross cutting of concerns, swapping out the user interfaces (i.e. windows for web) and of ease of unit testing.
Figure 1. MVC
In this pattern the controller has no reference to the view. Therefore we can swap out controllers and use the same controller for multiple views. The idea is the Controller handles events from the View, then manipulates the Model which raises events that cause the UI to update its own state.






Figure 2. MVP
Again three components but the dependencies change. Here the Presenter takes the onus to manipulate the model but also updates the view. The reference between the presenter and view is direct, as it knows about the view and makes changes on it.






Figure 3. MVVM

Introducing the ViewModel. Here we have replaced the Presenter with the View model. This pattern is really quite similar to the MVP pattern however there is one key difference. The relationship between the View and ViewModel is indirect. The View knows about the ViewModel, but the reverse is false. The result – clear cross cutting of concerns the View takes responsibility of how it looks where as the ViewModel takes responsibility of what data is displayed to the UI.
In the world of WPF the relationship between the View and ViewModel ideally should occur like this. View to ViewModel – the direction of this relationship should be governed by WPF Commands. ViewModel to View – the direction of this relationship is achieved by DataBinding via WPF dependency properties.

Anyway glad I got to the bottom of that!

WCF & MVVM

I was playing around attempting to implement course grained MVVM in WPF. I used the Prism Application Block to achieve the most part.

I came up with a few resulting base classes that formed the crux of the application I was deving at the time.

ViewModelBase does what it says on the tin. Your base class for ViewModels. Nothing really special apart from a couple of things. It contains a DelegateCommandManager which is a dictionary of commands that the ViewModel can support. Normally the implementors of the ICommand interface (i.e. RoutedCommand) has an event that gets fired internally within WPF when the result of the CanExecute has changed, it’s called 'CanExecuteChanged'. Surprise surprise.

I've addressed that in the following way. You'll notice an abstract property called 'AutoRaiseCanExecuteChangedOnPropertyChanged'. This means the derived the ViewModel gets to choose whether the event gets raised automatically once the OnPropertyChanged event is raised. You can inspect this in the RaisePropertyChanged method below.

Secondly the Dispatcher. Most of the work in the application is actually done on a background worker thread and some updates to the UI originate from there. To address this I've initialised the DisatcherSynchronizationContext within the base constructor below. I've made the basic assumption that the ViewModel should be newed up by the UI thread. Even when taking into consideration IOC, the first thread that runs is the WPF UI Thread and that should be the thread that new's up the IOC container. So I've covered all bases on that one.

        public abstract class ViewModelBase : DomainObject, IDisposable
    {
        protected ViewModelBase()
        {
            this.CommandManager = new DelegateCommandManager();
            this._Context = new DispatcherSynchronizationContext();
        }
        protected DelegateCommandManager CommandManager { get; private set; }
        protected virtual bool AutoRaiseCanExecuteChangedOnPropertyChanged
        {
            get { return false; }
        }
        protected override void RaisePropertyChanged(string propertyName)
        {
            base.RaisePropertyChanged(propertyName);
            if (!this.AutoRaiseCanExecuteChangedOnPropertyChanged) return;
            foreach(var command in this.CommandManager.Commands.Values)
            {
                command.RaiseCanExecuteChanged();
            }
        }
        protected DispatcherSynchronizationContext _Context;
       
        #region IDisposable
        private bool _Disposed; // to detect redundant calls
        protected virtual void Dispose(bool disposing)
        {
            if (this._Disposed) return;
            this._Disposed = true;
            if (disposing)
            {
                // dispose-only, i.e. non-finalizable logic
            }
            // shared cleanup logic
        }
        ~ViewModelBase()
        {
            Dispose(false);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }

You might have noticed the DomainObject class. Here’s the class definition -

    public abstract class DomainObject : NotificationObject, IDataErrorInfo
    {
        /// <summary>
        /// WPF does not use this property.
        /// </summary>
        public virtual string Error
        {
            get { return null; }
        }
        /// <summary>
        /// Use this to add custom validation for properties that are bound "OneWay". This is from source to target.
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public virtual string this[string columnName]
        {
            get { return null; }
        }
    }

Now this class can also be used to derive your Models. Pretty simply and self explanatory really.

Some of the obstacles I acountered during this was using third party controls that didn't support the WPF Command model. It’s a real pain in the butt when you're trying to implement pure MVVM. I came across the Expression Blend Behaviour Framework. It's pretty neat. Its a mechanism which allows you to extend controls to support new behaviour. Long story short, when you have controls which support .Net events and no WPF Commands we can use this framework to hook onto those events and invoke a WPF Command. All setup in XAML! I took this concept a step further and implemented a generic DotEventCommandBinder class which uses reflection to bind to an event and invoke a command.

Few limitations, it works only against 'Dot Net'events which supports the traditional Microsoft EventHandler Delegate only - void (object, EventArgs). It can support WPF Routed Events, but they need to be wrapped up in a Dot Net event wrapper. Luckily I think all Routed Events in the WPF framework are wrapped up with Dot Net events anyway. Finally it does not support AttachedRoutedEvents thats for sure !

/// <summary>
    /// This class binds a standard dot net event to a command.
    /// Supports delegate - 'void (object, EventArgs)'
    /// It does not bind to routed events that have not exposed a dot net event wrapper
    /// or attached routed events.
    /// </summary>
    public class DotNetCommandBinder : Behavior<UIElement>
    {
        public string EventSource
        {
            get { return (string)GetValue(EventSourceProperty); }
            set { SetValue(EventSourceProperty, value); }
        }
        // Using a DependencyProperty as the backing store for EventSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EventSourceProperty =
            DependencyProperty.Register("EventSource", typeof(string), typeof(DotNetCommandBinder));
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(DotNetCommandBinder));
        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
        // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(DotNetCommandBinder));
        private Delegate _commandHandler;
        private EventInfo _eventInfo;
        protected override void OnAttached()
        {
            if (string.IsNullOrEmpty(this.EventSource))
            {
                throw new NullReferenceException("EventSource cannot be null");
            }
            this._eventInfo = this.AssociatedObject.GetType().GetEvent(this.EventSource);
            if (this._eventInfo == null)
            {
                throw new NullReferenceException(string.Format("Could not find event on associated object with name {0}", this.EventSource));
            }
            try
            {
                var methodInfo = this.GetType().GetMethod("ActionCommand", BindingFlags.Instance|BindingFlags.NonPublic);
                this._commandHandler = Delegate.CreateDelegate(this._eventInfo.EventHandlerType, this, methodInfo, true);
                this._eventInfo.AddEventHandler(this.AssociatedObject, this._commandHandler);
            }
            catch(Exception ex)
            {
                throw new InvalidOperationException("Could not associate event handler to event. Please make sure your delegate signiture is 'void(object, EventArgs)'", ex);
            }
            base.OnAttached();
        }
        private void ActionCommand(object sender, EventArgs e)
        {
            if (this.Command != null && this.Command.CanExecute(this.CommandParameter))
            {
                this.Command.Execute(this.CommandParameter);
            }
        }
        protected override void OnDetaching()
        {
            if (this._eventInfo != null && this._commandHandler != null)
            {
                this._eventInfo.RemoveEventHandler(this.AssociatedObject, this._commandHandler);
            }
            base.OnDetaching();
        }
    }

Anyway I hope you've found that interesting. I'm going to take a look at the other frameworks outs there to check out if they offer any new fresh ideas into the world of WPF & MVVM.

  • MVVM Toolkit
  • MVVM Foundation
  • WPF Application Framework (WAF)
  • Light MVVM
  • Caliburn
  • Cinch