WPF : MVVM VS Project Template

This weekend I was going to finally write up all my pains and worries and problems solved in a neat MVVM mini framework, and was really looking forward to it, and then I opened my email, and there was one from Lester. It seems that Microsoft have finally created a Visual Studio template to get you up to speed when creating WPF MVVM apps. Read more about it over at Lesters Blog : http://blogs.msdn.com/llobo/archive/2009/05/01/download-m-v-vm-project-template-toolkit.aspx

I have tried this out, and if you are just getting to grips with the MVVM pattern there are a couple of good features in there, such as the overall project structure that is created, I think this is good. Here is what you get

Structure

I also like the fact that the ICommand implementation (DelegateCommand) uses WeakReferences.

   1:  #region ICommand Members
   2:   
   3:  /// <summary>
   4:  ///     ICommand.CanExecuteChanged implementation
   5:  /// </summary>
   6:  public event EventHandler CanExecuteChanged
   7:  {
   8:      add
   9:      {
  10:          if (!_isAutomaticRequeryDisabled)
  11:          {
  12:              CommandManager.RequerySuggested += value;
  13:          }
  14:          CommandManagerHelper.AddWeakReferenceHandler(
  15:              ref _canExecuteChangedHandlers, value, 2);
  16:      }
  17:      remove
  18:      {
  19:          if (!_isAutomaticRequeryDisabled)
  20:          {
  21:              CommandManager.RequerySuggested -= value;
  22:          }
  23:          CommandManagerHelper.RemoveWeakReferenceHandler(
  24:              _canExecuteChangedHandlers, value);
  25:      }
  26:  }
  27:   
  28:  bool ICommand.CanExecute(object parameter)
  29:  {
  30:      return CanExecute();
  31:  }
  32:   
  33:  void ICommand.Execute(object parameter)
  34:  {
  35:      Execute();
  36:  }
  37:   
  38:  #endregion

Notice the CommandManagerHelper class which looks like:

   1:  /// <summary>
   2:  ///     This class contains methods for the CommandManager that help avoid 
   3:  ///    memory leaks by using weak references.
   4:  /// </summary>
   5:  internal class CommandManagerHelper
   6:  {
   7:      internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
   8:      {
   9:          if (handlers != null)
  10:          {
  11:              // Take a snapshot of the handlers before we call out to them since the handlers
  12:              // could cause the array to me modified while we are reading it.
  13:   
  14:              EventHandler[] callees = new EventHandler[handlers.Count];
  15:              int count = 0;
  16:   
  17:              for (int i = handlers.Count - 1; i >= 0; i--)
  18:              {
  19:                  WeakReference reference = handlers[i];
  20:                  EventHandler handler = reference.Target as EventHandler;
  21:                  if (handler == null)
  22:                  {
  23:                      // Clean up old handlers that have been collected
  24:                      handlers.RemoveAt(i);
  25:                  }
  26:                  else
  27:                  {
  28:                      callees[count] = handler;
  29:                      count++;
  30:                  }
  31:              }
  32:   
  33:              // Call the handlers that we snapshotted
  34:              for (int i = 0; i < count; i++)
  35:              {
  36:                  EventHandler handler = callees[i];
  37:                  handler(null, EventArgs.Empty);
  38:              }
  39:          }
  40:      }
  41:   
  42:      internal static void AddHandlersToRequerySuggested(
  43:         List<WeakReference> handlers)
  44:      {
  45:          if (handlers != null)
  46:          {
  47:              foreach (WeakReference handlerRef in handlers)
  48:              {
  49:                  EventHandler handler = handlerRef.Target as EventHandler;
  50:                  if (handler != null)
  51:                  {
  52:                      CommandManager.RequerySuggested += handler;
  53:                  }
  54:              }
  55:          }
  56:      }
  57:   
  58:      internal static void RemoveHandlersFromRequerySuggested(
  59:         List<WeakReference> handlers)
  60:      {
  61:          if (handlers != null)
  62:          {
  63:              foreach (WeakReference handlerRef in handlers)
  64:              {
  65:                  EventHandler handler = handlerRef.Target as EventHandler;
  66:                  if (handler != null)
  67:                  {
  68:                      CommandManager.RequerySuggested -= handler;
  69:                  }
  70:              }
  71:          }
  72:      }
  73:   
  74:      internal static void AddWeakReferenceHandler(
  75:        ref List<WeakReference> handlers, EventHandler handler)
  76:      {
  77:          AddWeakReferenceHandler(ref handlers, handler, -1);
  78:      }
  79:   
  80:      internal static void AddWeakReferenceHandler(
  81:        ref List<WeakReference> handlers, EventHandler handler, 
  82:        int defaultListSize)
  83:      {
  84:          if (handlers == null)
  85:          {
  86:              handlers = (defaultListSize > 0 ? new 
                   List<WeakReference>(defaultListSize) : new List<WeakReference>());
  87:          }
  88:   
  89:          handlers.Add(new WeakReference(handler));
  90:      }
  91:   
  92:      internal static void RemoveWeakReferenceHandler(
  93:        List<WeakReference> handlers, EventHandler handler)
  94:      {
  95:          if (handlers != null)
  96:          {
  97:              for (int i = handlers.Count - 1; i >= 0; i--)
  98:              {
  99:                  WeakReference reference = handlers[i];
 100:                  EventHandler existingHandler = reference.Target as EventHandler;
 101:                  if ((existingHandler == null) || (existingHandler == handler))
 102:                  {
 103:                      // Clean up old handlers that have been collected
 104:                      // in addition to the handler that is to be removed.
 105:                      handlers.RemoveAt(i);
 106:                  }
 107:              }
 108:          }
 109:      }
 110:  }

 

I think I could be tempted to use this from now on. And one more thing I like is the CommandReference class which allows a Key to be associated with an ICommand in XAML like

   1:  <Window x:Class="WpfModelViewApplication1.Views.MainView"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:c="clr-namespace:WpfModelViewApplication1.Commands"
   5:      Title="Main Window" Height="400" Width="800">
   6:      
   7:      <Window.Resources>
   8:          <!-- Allows a KeyBinding to be associated with a 
   9:          command defined in the View Model  -->
  10:          <c:CommandReference x:Key="ExitCommandReference" 
  11:                              Command="{Binding ExitCommand}" />
  12:      </Window.Resources>
  13:     
  14:      <Window.InputBindings>
  15:          <KeyBinding Key="X" Modifiers="Control" 
  16:                      Command="{StaticResource ExitCommandReference}" /> 
  17:      </Window.InputBindings>
  18:      
  19:      <DockPanel>
  20:          <Menu DockPanel.Dock="Top">
  21:              <MenuItem Header="_File">
  22:                  <MenuItem Command="{Binding ExitCommand}" Header="E_xit" 
  23:                            InputGestureText="Ctrl-X" />
  24:              </MenuItem>
  25:          </Menu>
  26:      
  27:          <Grid>
  28:              <!-- Add additional content here -->
  29:          </Grid>
  30:      </DockPanel>
  31:  </Window>

But as for the rest, it is nothing that the WPF Disciples have not been doing for ages. What I am really disappointed by, is the lack of thought about services such : OpenFile/MessageBox/OpenDialog etc etc.

These are very very important, and far harder to get right that the basics.

In closing, I would say this is a step in the right direction, but some work still needs to be done to bridge the gap. I am not saying a full blown CAL/Prism template is required, but thought needs to be given to services. This is what is most likely to trips newbie WPFers up, I mean I have been working with WPF a while now, and I only just get it. What hope has a newbie got.

Looks like I will be writing my stuff up after all. Yipee

10 Comments so far »

  1. tawani said

    am May 2 2009 @ 2:10 pm

    You know Saacha, I actually came immediately to your site to see if anybody had commented on the lack of UI services (OpenFile/MessageBox/OpenDialog etc etc.).

    It is a great simple framework for starters, but I still think they should have added a simple “MessageBox” to the example.

  2. Marlon Grech said

    am May 3 2009 @ 8:28 am

    did u really like it??? for me it has nothing in their but the DelegateCOmmand… something that has been in the community ages ago…

    am I missing something??

  3. sacha said

    am May 3 2009 @ 2:52 pm

    Tawani

    Yeah they missed a trick for sure. Ill be working on my own framework very soon. I find their lack of faith in services disturbing

    PS :
    I will be writing a book soon, which would be cool I hope.

  4. sacha said

    am May 3 2009 @ 2:53 pm

    Marlon

    This template has nothing for dudes like you, but for absolute beginners, I can its benefit, at least a firm structure and good base point is created.

  5. Templeton said

    am May 14 2009 @ 4:51 pm

    Hi Sacha,
    I’m a new reader of your blog. I started using WPF some months ago and I have a dude with WPF. I was searching your e-mail but didn’t find it :(

    I wanna show objects in a Window.
    I have some objects and I created datatemplates for them. To show the objects I create labels and instance the objects into its content.
    ¿Is it a good practice? ¿Is there a better solution?

    ¡Thanks!

  6. sacha said

    am May 14 2009 @ 7:11 pm

    Templeton,

    I do not understand what you are asking. But I have to say I do not have time to field open ended questions like this, if a question is raised against a blog/article I always try to answer it, but I do not have time to help everyone.

  7. Gites France said

    am August 7 2009 @ 10:25 am

    The template works well for me. Thanks – I appreciate what you are doing.

  8. sacha said

    am August 7 2009 @ 10:29 am

    Gites

    I think that template is just ok to be honest. You could check out my Cinch MVVM framework for a fuller MVVM implemented library.

    http://sachabarber.net/?p=522

  9. Tina said

    am January 17 2010 @ 11:43 am

    How is Cinch differed from Josh Smith MVVM library? just curious because I haven’t read either one.

  10. sacha said

    am January 17 2010 @ 1:03 pm

    Joshs is very light weight, and offers a few things like INotifyPropertyChanged (INPC), PropertyObserver, RelayCommand and Mediator. Cinch offers all this and many more things, such as threading helpers, attached behaviours and IOC services and test services as well. Better INPC property generators using expression trees, and also DataWrappers to allow VM to control every bit of editable datas state

    Oh and CInch has good documentation and a code generator.

Comment RSS · TrackBack URI

Leave a comment

Name: (Required)

eMail: (Required)

Website:

Comment: