Feeds:
Posts
Comments

Archive for September, 2007

Revisting the CommandModel

Recently, I’ve been revisiting the concept of the CommandModel.  I’ve posted about this before here and here.  I’m a firm believer in using the Model-View-ViewModel in WPF, and I tried following along with the code presented by the folks who should be experts here.  However, from the very beginning I had problems with the examples posted that used a CommandModel to represent the commands that would be carried out in response to UI events.  I thought the troubles lied in the implementations.  After all, they were simple examples and it was reasonable to assume they just didn’t live up to use in production with out appropriate tweaking.  That’s what led to the previous posts I made on this subject.  My final conclusion (prior to now) about this topic was that when implementing a CommandModel you should base it on ICommand instead of RoutedCommand.  This solved the problems I had encountered thus far, and seemed like a good implementation.

Then it fell apart.  See, RoutedCommand and RoutedUICommand offer you a lot of functionality you don’t get from ICommand.  I knew that when I made the last post, of course, but the only feature I took into account at the time was the event routing, which I didn’t need.  Well, there’s other features that are harder to do without.  For instance, the simple fact that a RoutedUICommand has properties that can be used to set the text on a menu item is something that goes a long way towards keeping your XAML simple and clean.  I could do with out this, of course, but it bothered my sensibilities.  However, more important is the fact that you can add gestures, such as keyboard shortcuts, to a RoutedUICommand.  That’s functionality I can’t do without.  So the simple ICommand solution isn’t sufficient.  Bummer.  Back to the drawing board.

This time, however, I took a healthy pause to think about the concept from the design perspective, instead of from the implementation perspective.  This proved to be enlightening, since I now think the whole concept of a CommandModel is flawed, and we shouldn’t be using them!

Just from a high level concept, they are flawed.  What is a CommandModel?  It’s a model of a command.  So, what’s a model, then?  A model defines data and behaviors for some given domain.  There’s very little data involved here, there’s really only behavior.  So I’m reluctant to call this a model at all.  As far as the behavior is concerned… we already have plenty of concepts that can represent the behavior just fine, from delegates to Events to ICommands and it’s derivatives.  What need do we really have to create yet another variant here?

OK, so with that in mind, let’s look at why the CommandModel was created.  Of course, I can only guess here, since I didn’t create it and I’m not privy to the inside information about why the creators thought it was needed.  So, let’s just analyze what we get out of a CommandModel.

Definition of behavior.

OK, as I already pointed out, we already have alternatives for this, so that can’t be the reason to have a CommandModel.  Not to mention, as I pointed out before, the original designs for CommandModel did a poor job here, since they required a tight coupling to the ViewModel.  I resolved that issue, but I think it’s evidence that this isn’t the reason the CommandModel was invented.

Wiring of UI events to behavior.

Well, since this was one of the major issues I had with the original examples, I don’t think this could be the reason.  Or, at least, if it was the reason, I think the wrong solution was used.  See, the CommandModel itself doesn’t help here.  The examples used another concept, an attached property, to create the CommandBindings.  This works, but it’s clumsy and verbose, and doesn’t really require a CommandModel to work.  More importantly, there’s a better solution (which I’ll detail below).  So, if this was the reason, then the wrong solution was chosen.

Allow testing without the need for a UI.

This is important.  This is one of the main reasons that Model-View-ViewModel itself is such a useful pattern.  However, all it really exposes to help us here are OnQueryEnabled and OnExecute methods that can be called.  That’s it.  When you think about that, it means it doesn’t really provide us with anything, because we can expose the event handlers within our ViewModel instead.  Heck, with reflection we don’t even have to expose them.  The event handlers are already testable, with out the need for a CommandModel.

No, I’ve come to the conclusion that the CommandModel is a flawed design, and I won’t be using it anymore.  Instead, my ViewModels will expose the normal RoutedCommands.  Then they’ll implement the necessary event handlers for ExecutedRoutedEventHandler and CanExecuteRoutedEventHandler, which can be unit tested.  All that’s left is to create the CommandBindings, which can be done in the ViewModel’s constructor, thanks to the ViewModelExtension.  This even makes it easy to create the CommandBindings for the standard commands provided by WPF, which is a very nice bonus.

So, if you’re following the Model-View-ViewModel pattern, take my advice and excise the concept of the CommandModel.  You’re design will benefit from it.  If your not following the Model-View-ViewModel pattern, take my advice and reconsider :).

Advertisements

Read Full Post »

ViewModelExtension

Dr. WPF has an interesting blog entry with a MarkupExtension that allows you to reference other objects within the object tree.  It is a nice extension (there are others posted around that do similar things, see the comments on that blog entry for some others).  However, what I found interesting was the specific use case scenario for which Dr. WPF is suggesting the MarkupExtension would be useful.  Why?  Because this use case scenario is the exact same scenario you often find yourself in when trying to use a ViewModel.  You want to set the Window’s (or Page or whatever is your root object) DataContext to a new instance of the ViewModel, and said ViewModel might need a reference to the Window in order to do things like specify the parent of dialogs created in ViewModelCommand handlers.  Dr. WPF’s ObjectReference stuff would work here, but it seems overly engineered for what we’re doing here.  I already had a solution that I had been using prior to his post, that I called ViewModelExtension.  Using the ViewModelExtension I can solve the exact problem from his blog entry with code like the following:
 

<Grid Name="RssGrid">

  <ListBox DataSource="{loc:ViewModel rss:RssFeeder}"

      ItemsSource="{Binding Path=RecentPosts}" />

</Grid>

The code for this extension is relatively straightforward:

public class ViewModelExtension : MarkupExtension
{
   public ViewModelExtension()
   {
   }

   public ViewModelExtension(Type modelType)
   {
      type = modelType;
   }

   Type type;
   public Type ModelType
   {
      get { return type; }
      set { type = value; }
   }

   public override object ProvideValue(IServiceProvider provider)
   {
      IProvideValueTarget provideValue = provider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
      object target = provideValue.TargetObject;
      ConstructorInfo cons = ModelType.GetConstructor(new Type[] { target.GetType() });
      if (cons != null)
         return cons.Invoke(new object[] { target });
      cons = ModelType.GetConstructor(Type.EmptyTypes);
      if (cons != null)
         return cons.Invoke(null);
      return null;
   }
}

The general idea here is that the ViewModelExtension will instantiate an object of the type you specify.  It does so by calling a constructor that takes an object of the type of the TargetObject if one exists, or the default constructor otherwise.  This extension has many of the same drawbacks as the ObjectReference extension, since it isn’t a binding either.  It also doesn’t have all of the funtionality of the ObjectReference, so it can’t be used in all of the same scenarios.  However, for this typical scenario it turns out to be a much simpler and cleaner solution.

I’d love to hear your thoughts on this one.

Read Full Post »