Yet another blog about WPF, Surface, SL, MVVM, NUI....

2011

2010

2009

2008

Tag - Design pattern

Entries feed - Comments feed

 

Binding to the selected items of a ListBox (or an another items controls)

13 June 2010

A problem you often meet when using MVVM is to get the selected items of an items control, especially Listbox.

You can easily bind the selected item or the current items but when multi selection comes in the way, it becomes harder because the SelectedItems (with an 's' property is not available to binding).

In this article we will discover an easy way to bind yourself with an attached property to the SelectedItems property of the ListBox control.



We will use the Ramora pattern discussed before to bind ourself to the ListBox's selectionChanged events and then update the target list when the selection change.

If the target list implements INotifyCollectionChanged we will update the listbox selection when this event is raised.

Here is the resulting code :

public class ListBoxSelectedItemsSyncher : DependencyObject
{
  private static List<Syncher> _synchers = new List<Syncher>();
 
  #region ListToSync
 
  /// <summary>
  /// ListToSync Attached Dependency Property
  /// </summary>
  public static readonly DependencyProperty ListToSyncProperty =
    DependencyProperty.RegisterAttached("ListToSync", 
	             typeof(IList), typeof(ListBoxSelectedItemsSyncher),
      new FrameworkPropertyMetadata((IList)new List<Object>(),
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
		       new PropertyChangedCallback(OnListToSyncChanged)));
 
 
  private static void OnListToSyncChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    ListBox listBox = d as ListBox;
 
    if(!(d is ListBox)
     throw new ArgumentException("ListBoxSelectedItemsSyncher is only applyable to Listbox");
 
    Syncher synch = (from Syncher syncher 
	              in _synchers where syncher.ListBox == listBox select syncher)
                             .FirstOrDefault();
    if (synch != null)
    {
      synch.ListToSync = e.NewValue as IList;
    } else
    {
      synch = new Syncher(listBox, e.NewValue as IList);
      _synchers.Add(synch);
      listBox.Unloaded += new RoutedEventHandler(listBox_Unloaded);
    }
  }
 
  static void listBox_Unloaded(object sender, RoutedEventArgs e)
  {
    ListBox listBox = sender as ListBox;
    Syncher synch = (from Syncher syncher 
	              in _synchers where syncher.ListBox == listBox select syncher)
                      .FirstOrDefault();
    if (synch != null)
    {
      _synchers.Remove(synch);
      synch.Dispose();
      synch = null;
    }
  }
 
  /// <summary>
  /// Gets the ListToSync property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static IList GetListToSync(DependencyObject d)
  {
    return (IList)d.GetValue(ListToSyncProperty);
  }
 
  /// <summary>
  /// Sets the ListToSync property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static void SetListToSync(DependencyObject d, IList value)
  {
    d.SetValue(ListToSyncProperty, value);
  }
 
  #endregion
 
 
  internal class Syncher : IDisposable
  {
 
    private ListBox _listbox;
    public ListBox ListBox { get { return _listbox; } }
 
    private IList _listToSync;
    public IList ListToSync
    {
      get { return _listToSync; }
 
      set
      {
        detachTheListToSynch();
        _listToSync = value;
        attachTheListToSynch();
      }
    }
 
    public Syncher(ListBox listbox, IList listToSync)
    {
      _listbox = listbox;
      _listToSync = listToSync;
      attachTheListToSynch();
    }
 
    void collectionChangedList_CollectionChanged(object sender,
                        	NotifyCollectionChangedEventArgs e)
    {
      //Add new items   
      if (e.NewItems != null)
      {
        foreach (Object item in e.NewItems)
        {
          _listbox.SelectedItems.Add(item);
        }
      }
      if (e.OldItems != null)
      {
        foreach (Object item in e.OldItems)
        {
          _listbox.SelectedItems.Remove(item);
        }
      }
 
      if (e.Action == NotifyCollectionChangedAction.Reset)
        _listbox.SelectedItems.Clear();
 
      CommandManager.InvalidateRequerySuggested();
    }
 
    void _list_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      if (_listToSync != null)
      {
        //Add new items                   
        foreach (Object item in e.AddedItems)
        {
          _listToSync.Add(item);
        }
        foreach (Object item in e.RemovedItems)
        {
          _listToSync.Remove(item);
        }
        CommandManager.InvalidateRequerySuggested();
      }
    }
 
    #region IDisposable Members
    public void Dispose()
    {
      if (_listbox == null) return;
      _listbox.SelectionChanged -= _list_SelectionChanged;
      detachTheListToSynch();
      _listbox = null;
    }
    #endregion
 
    #region private methods
    private void attachTheListToSynch()
    {
      _listbox.SelectionChanged -= _list_SelectionChanged;
      if (_listToSync == null) return;
 
      INotifyCollectionChanged collectionChangedList = null;
      if ((collectionChangedList = _listToSync as INotifyCollectionChanged) != null)
        collectionChangedList.CollectionChanged 
	  += new NotifyCollectionChangedEventHandler(collectionChangedList_CollectionChanged);
 
      //Update the selection with the new list
      _listbox.SelectedItems.Clear();
 
      foreach (var item in _listToSync)
        _listbox.SelectedItems.Add(item);
 
      _listbox.SelectionChanged 
	       += new SelectionChangedEventHandler(_list_SelectionChanged);
    }
 
    private void detachTheListToSynch()
    {
      INotifyCollectionChanged collectionChangedList = null;
      if ((collectionChangedList = _listToSync as INotifyCollectionChanged) != null)
        collectionChangedList.CollectionChanged -= collectionChangedList_CollectionChanged;
    }
    #endregion
 
  }
 }


Here we are.

Edit : I found out later an another version of the same feature made by Samuel Jack on his blog : http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html !



Shout it kick it on DotNetKicks.com


 

MVVM - Creating ViewModel : create dynamic proxies with Castle (solution 3 of n)

11 March 2010

Here is the next episode of our serie MVVM - Creating ViewModel. A list of all the article about creating a ViewModel is here..

Today we are going to see how to create dynamic proxies for our business objects.

What are Dynamic proxies ?

Readers in a hurry can directly jump to the third part "An implementation".

Proxies are a Desing Pattern which is used a lot in our computer programming world. Here is the Wikipedia definition :

A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.


The easiest example to understand I have found is sunglasses. The sunglasses are a proxy between the real world (with all the funky colors) and the world you see trough them (where everything is grey/brown)... You also noticed that the proxy is not neutral, it adds a behaviors(here the gray filter on your vision), but this is not mandatory.
Note : Laurent pointed out that he prefers the TV analogy to explain proxies but I prefer the sunglasses which there is no transformations 3D to 2D.

Proxies

With this in mind let met introduce some vocabulary :

  • The subject: this is the proxied object. In our case : the real world,
  • The client: this is the object which wants to use the subject. In our case : the one who wear the sunglasses,
  • The proxy: this is the object used by the client and which uses the subject. In our case : the sunglasses,
  • The behaviors/interceptors: this is a behavior that the subject does not have and that the proxy creates. In a program, a common interceptor is a logger which tells the start and the end of a method.


Behavior algo example :

public void loggerExampleBehavior(Method theMethod){
  Log("Before method execution.");
  //Execution of the method
  Log("After method execution.");
}


So how to use them for our ViewModel ?(theory)

Readers in a hurry can directly jump to the third part "An implementation".

To be brief : we will add the INotifyPropertyChanged behavior to the business objects by creating a dynamicProxy. We will then no more use directly the business object but the proxies of/to them.
We will so launch the PropertyChangedEvent for each call made to a setter of the business object. Pretty simple ? proxies_INotify_logic.jpg

An implementation with Castle dynamicProxy (code)


To implement the proxy pattern dynamicly we will use Castle Dynamic Proxy. This framework is pretty simple to use as you'll see.

There is only one limitation : properties of your business object must be marked as virtual.

Creation of the proxy

To create our proxy I declare a static method. This method is generic and make any object send NotifyPropertyChanged events on setter calls. The differents class used will be described later.

public class ProxyCreator
{
  public static T MakeINotifyPropertyChanged<T>() where T : class, new()
  {
    //Creates a proxy generator
    ProxyGenerator proxyGen = new ProxyGenerator();
 
    //Generates a proxy using our Interceptor and implementing INotifyPropertyChanged
    var proxy = proxyGen.CreateClassProxy(
      typeof(T),
      new Type[] { typeof(INotifyPropertyChanged) },
      ProxyGenerationOptions.Default,
      new NotifierInterceptor()
      );
 
    return proxy as T;
  }
}

The interceptor


The interceptor does two main things :

  1. It exposes a PropertyChangedEventHandler,
  2. It raises the PropertyChangedEventHandler event when a setter is called with the good name.



Also, I have cached the PropertyChangedEventArgs for better performance.

public class NotifierInterceptor : IInterceptor
{
  private PropertyChangedEventHandler handler;
  public static Dictionary<String, PropertyChangedEventArgs> _cache =
    new Dictionary<string, PropertyChangedEventArgs>();
 
  public void Intercept(IInvocation invocation)
  {
    //Each subscription to the PropertyChangedEventHandler is intercepted (add)
    if (invocation.Method.Name == "add_PropertyChanged")
    {
      handler = (PropertyChangedEventHandler)
            Delegate.Combine(handler, (Delegate)invocation.Arguments[0]);
      invocation.ReturnValue = handler;
    }
    //Each de-subscription to the PropertyChangedEventHandler is intercepted (remove)
    else if (invocation.Method.Name == "remove_PropertyChanged")
    {
      handler = (PropertyChangedEventHandler)
         Delegate.Remove(handler, (Delegate)invocation.Arguments[0]);
      invocation.ReturnValue = handler;
    }
    //Each setter raise a PropertyChanged event
    else if (invocation.Method.Name.StartsWith("set_"))
    {
      //Do the setter execution
      invocation.Proceed();
      //Launch the event after the execution
      if (handler != null)
      {
        PropertyChangedEventArgs arg =
          retrievePropertyChangedArg(invocation.Method.Name);
        handler(invocation.Proxy, arg);
      }
    }
    else invocation.Proceed();
  }
 
  // Caches the PropertyChangedEventArgs
  private PropertyChangedEventArgs retrievePropertyChangedArg(String methodName)
  {
    PropertyChangedEventArgs arg = null;
    NotifierInterceptor._cache.TryGetValue(methodName, out arg);
    if (arg == null)
    {
      arg = new PropertyChangedEventArgs(methodName.Substring(4));
      NotifierInterceptor._cache.Add(methodName, arg);
    }
    return arg;
  }
}

How we use it in the application


We'll only have to expose the proxies to our views with a little snippet of code :

MyBusinessObject myBusinessObject;
DataContext = myBusinessObject = ProxyCreator.MakeINotifyPropertyChanged<MyBusinessObject>();

Interesting links




Shout it kick it on DotNetKicks.com



 

MVVM - Creating ViewModel tutorial

MVVM - Creating ViewModel is a serie of blogposts that talk in details about various ways to create a ViewModel to use it with the MVVM pattern.

You often do not create the business object used by the application which are created by another team and that these objects are not ready for binding.

So you must find a solution to create an object which will in fact be very similar of your business object BUT ready for binding. These posts describe the differents solutions you have in hand.


So far the following parts have been published:

  1. Wrap your business object
  2. Use XAML Power Toys
  3. Create dynamic proxies
  4. Use the object builder of CAB
  5. Generate IL code (TO DO)



If you have other solution, don't forget to tell about in the comments !





 

MVVM - How to integrate the Office Ribbon respecting the pattern (especially the commands)

4 March 2010

Synopsis

The ribbon controls - introduced by office 2007 -are available for free on the Microsoft Office web site (French users should set the language to "english" to access the ressources). They can leverage the user's experience of your application and are pretty simple to use.

When I wanted to add them into one of my application I realized that it was broking the M-V-VM pattern.

In this post, we will see how to use the Ribbon, then what exactly is the issue and finally examine the solution I use as a work-around.

How to use the ribbon

This is very easy, here are the steps :

  • Download the library on the web site (http://msdn.microsoft.com/fr-fr/office/aa973809.aspx),
  • Add a reference to the dll in your project and dclare in the XAML this XML namespace : clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary
  • Then you are free to use the ribbon's controls.


A central part of the Ribbon library is the RibbonCommand. A RibbonCommand is a WPF command plus a lot of things related to how it's presented : a label, a description, an large image, a small image, etc.... Then every button, combobox, checkbox, ... used in the Ribbon use these infos to change the way they are presented. Here is a little example : MVVMRibbonExample

<Window x:Class="MVVMRibbon.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
    Title="MainWindow" Height="350" Width="525">
 
  <Window.Resources>
    <r:RibbonCommand x:Key="MyFirstCommand" LabelTitle="A command"
        LabelDescription="A command description"
        LargeImageSource="/MVVMRibbon;component/antoine64x64.jpg"
        SmallImageSource="/MVVMRibbon;component/antoine64x64.jpg"
        Executed="RibbonCommand_Executed" CanExecute="RibbonCommand_CanExecute" />
 
    <r:RibbonCommand x:Key="ApplicationMenuCommand"
        LargeImageSource="/MVVMRibbon;component/antoine64x64.jpg"
        SmallImageSource="/MVVMRibbon;component/antoine64x64.jpg" />
  </Window.Resources>
 
  <DockPanel LastChildFill="True">
    <r:Ribbon DockPanel.Dock="Top">
      <!--I hide the QuickAccessToolBar because I have no use of it-->
      <r:Ribbon.QuickAccessToolBar>
        <r:RibbonQuickAccessToolBar Visibility="Collapsed" />
      </r:Ribbon.QuickAccessToolBar>
 
      <!--Here is the ApplicationMenu : the bubble acting as a main menu in Office-->
      <r:Ribbon.ApplicationMenu>
        <r:RibbonApplicationMenu  Command="{StaticResource ApplicationMenuCommand}" />
      </r:Ribbon.ApplicationMenu>
 
      <!-- And finally the well-know "tabs"-->
      <r:RibbonTab Label="A first tab">
        <!--The controls are grouped in the tabs-->
        <r:RibbonGroup>
          <r:RibbonButton Command="{StaticResource MyFirstCommand}" />
        </r:RibbonGroup>
      </r:RibbonTab>
 
      <r:RibbonTab Label="A second tab"></r:RibbonTab>
    </r:Ribbon>
 
    <FlowDocumentReader />
  </DockPanel>
</Window>


Why using the RibbonCommand is broking the pattern

As you can see in the code above, when you declare the RibbonCommands in the XAML, you have to set a Execute and CanExecute event's handler. These handlers are set in the code behind and this is what breaks the pattern.

Sow why not only declare RibbonCommand inside the viewModels ? Because this will put presentation informations (those inside the RibbonCommand like images, description) inside the ViewModel which one must be decoupled from the way the data is presented.

Actually, only declaring RibbonCommands inside the ViewModel breaks the pattern because it exist a very strong link between the data and how it's presented in these objects.

An another thing is that you can't bind anything to the Ribbon commands because : A 'Binding' cannot be set on the 'XXX' property of type 'RibbonCommand'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.... Yes, a RibbonCommand is not a DependencyObject.

So I can't use the ribbon ?

Nooooo ! A solutions exists : first you can create some kind of proxies to the command which will make the commands available as a ressource in the views(CommandReference) through binding. Then the view will be responsible to create the RibbonCommands as they which from these commands in the ressources. To this purpose we'll have to extend the standard RibbonCommand to make them accepts a Command as a property.

Ok, ok, I heard your question : why not directy make the extended RibbonCommands acts as a proxy ? The answere is that RibbonCommand does not inherits from DependencyObject and so we can't bind anything on it :-( ! (Which means, by the way, that we can't bind the commands of the viewModels directly to them).

I did not invent this technique, it's from :



The proxy for the commands

As pointed out in this article I call them CommandReference.

We declare a DependencyProperty on which we will bind the command in the ViewModel. As you can see, this class is also a ICommand : all the calls will be translated to the binded command.

public class CommandReference : Freezable, ICommand
{
public static readonly DependencyProperty CommandProperty = 
  DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference), 
     new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
public ICommand Command
{
  get { return (ICommand)GetValue(CommandProperty); }
  set { SetValue(CommandProperty, value); }
}
 
#region ICommand Members
public bool CanExecute(object parameter){ 
  return (Command != null) ?Command.CanExecute(parameter):false;
}
 
public void Execute(object parameter){ Command.Execute(parameter);}
 
public event EventHandler CanExecuteChanged;
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  CommandReference commandRef = d as CommandReference;
  if (commandReference != null)
  {
	ICommand lastCommand = e.OldValue as ICommand;
	if (oldCommand != null) lastCommand .CanExecuteChanged -= commandRef .CanExecuteChanged;
 
	ICommand nextCommand = e.NewValue as ICommand;
	if (newCommand != null) nextCommand .CanExecuteChanged += commandRef .CanExecuteChanged;
  }
}
#endregion
 
#region Freezable
protected override Freezable CreateInstanceCore()
{
  return new CommandReference();
}
#endregion

The extended RibbonCommands

We simply add a ICommand property to the RibbonCommand wich one we will be abble to fill in with a StaticRessource.

public class RibbonCommandExtended : RibbonCommand
{
  private ICommand _command;
  public ICommand Command
  {
    get { return _command; }
    set
    {
      _command = value;
      if (_command != null)
      {
        this.CanExecute += us_CanExecute;
        this.Executed += us_Executed;
      }
      else
      {
        this.CanExecute -= us_CanExecute;
        this.Executed -= us_Executed;
      }
    }
  }
 
  private void us_Executed(object sender, ExecutedRoutedEventArgs e)
  {
    Command.Execute(e.Parameter);
  }
 
  private void us_CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
    e.CanExecute = Command.CanExecute(e.Parameter);
  }
}


Then, what will my XAML looks like .

Here it is, especially for you, very simple :

<Window.Resources>
  <fwk:CommandReference x:Key="MyCommandReference"
      Command="{Binding MyViewModelCommand}" />
  <fwk:RibbonCommandExtended x:Key="cmd_MyCommand" LabelTitle="A labek"
      LabelDescription="A description"
      Command="{StaticResource MyCommandReference}"
      LargeImageSource="/MVVMRibbon;component/antoine64x64.jpg"
      SmallImageSource="/MVVMRibbon;component/antoine64x64.jpg" />
</Window.Resources>

Then you use the RibbonCommandExtended as you will have used the standard RibbonCommand.

Isn't it a little long to make something pretty simple ? The answer is definitively yes but the Microsoft seems to be working on new version of the ribbon which will respects the M-V-VM pattern...

Why not using our RamoraPattern ?

This is not possible because as I pointed out before, the RibbonCommands are not DependencyObject and so we can't attach properties to them :-( !



Links

Here are some links you may find interesting on the same subjects :


Shout it kick it on DotNetKicks.com



 

MVVM : How to keep collections of ViewModel and Model in sync

2 March 2010

As pointed out in this post collections of the ViewModels and the models are not sync. This is because we do not access directly to the model but to an ObservableCollection(in the viewModel) which contains the object of the original collection(in the model) and that these two collections are not the same...

As pointed out in the comments on CodeProject, there is work-around. I try here to present two of them !

A first solution : register to the wrapping collection changes

The first solution is to register to the events of the ObservableCollection in your ViewModel and to translate the changes to the wrapped collection.
It is very straighforward but it becomes very fastidious if you have a lot of collections to deal with.

Here is the code :

//Wrap the business object collection
_friendsName = new ObservableCollection<string>(myBusinessObject.FriendsName);
//Register to the wrapping CollectionChanged event
_friendsName.CollectionChanged += new NotifyCollectionChangedEventHandler(_friendsName_CollectionChanged);
 
...
 
//Translate the changes to the underlying collection
void _friendsName_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
 switch (e.Action)
 {
  case NotifyCollectionChangedAction.Add:
   _myBusinessObject.FriendsName.AddRange(
    e.NewItems.OfType<String>()
    );
   break;
  case NotifyCollectionChangedAction.Remove:
   _myBusinessObject.FriendsName.RemoveAll(
    friendName => e.OldItems.Contains(friendName)
    );
   break;
  //Reset = Clear
  case NotifyCollectionChangedAction.Reset:
   _myBusinessObject.FriendsName.Clear();
   break;
 }
}



Another solution : create a proxy

You also can create a class which will act as a Proxy to the businessObject. Its only function will be to leverage the INotifyCollectionChanged events when necessary. I called it MVMCollectionSyncher for ModelViewModelCollectionSyncher and here is the code (which is very straightforward) :

public class MVMCollectionSyncher<T> : ICollection<T>, IDisposable, INotifyCollectionChanged
{
 #region fields
 private ICollection<T> _wrappedCollection;
 #endregion
 
 public MVMCollectionSyncher(ICollection<T> wrappedCollection)
 {
  if (wrappedCollection == null)
   throw new ArgumentNullException(
    "wrappedCollection",
    "wrappedCollection must not be null.");
  _wrappedCollection = wrappedCollection;
 }
 
 #region ICollection<T> Members
 public void Add(T item)
 {
  _wrappedCollection.Add(item);
  FireCollectionChanged(
   new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
 }
 
 public void Clear()
 {
  FireCollectionChanged(
   new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  _wrappedCollection.Clear();
 }
 
 public bool Contains(T item)
 {
  return _wrappedCollection.Contains(item);
 }
 
 public void CopyTo(T[] array, int arrayIndex)
 {
  _wrappedCollection.CopyTo(array, arrayIndex);
 }
 
 public int Count
 {
  get { return _wrappedCollection.Count; }
 }
 
 public bool IsReadOnly
 {
  get { return _wrappedCollection.IsReadOnly; }
 }
 
 public bool Remove(T item)
 {
  if (_wrappedCollection.Remove(item)) {
   FireCollectionChanged(
     new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
   return true;
  }
  return false;
 }
 
 #endregion
 
 #region IEnumerable<T> Members
 public IEnumerator<T> GetEnumerator()
 {
  return _wrappedCollection.GetEnumerator();
 }
 #endregion
 
 #region IEnumerable Members
 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
 {
  return _wrappedCollection.GetEnumerator();
 }
 #endregion
 
 #region INotifyCollectionChanged Members
 public event NotifyCollectionChangedEventHandler CollectionChanged;
 private void FireCollectionChanged(NotifyCollectionChangedEventArgs eventArg)
 {
  NotifyCollectionChangedEventHandler handler = CollectionChanged;
  if (handler != null) handler.Invoke(this, eventArg);
 }
 #endregion
 
 #region IDisposable Members
 public void Dispose() { _wrappedCollection = null; }
 #endregion
}



Then in your ViewModel instead of presenting an ObservableCollection<> you offer an MVMCollectionSyncher with this code.

//Creation
MVMCollectionSyncher _friendsName = new MVMCollectionSyncher<string>(myBusinessObject.FriendsName);
...
//Property
public MVMCollectionSyncher<String> FriendsName
{
 get { return _friendsName; }
 set
 {
  if (value != null){
   _friendsName.Dispose();
   _friendsName = value;
   FirePropertyChanged("FriendsName");
  }
 }
}



Here are some links dealing on the same subject :



Shout it kick it on DotNetKicks.com
 

MVVM - Creating ViewModel : use XAML Power Toys (solution 2 of n).

Here is the next episode of our serie MVVM - Creating ViewModel. A list of all the article about creating a ViewModel is here..

Today we are going to discover a tool which can help us to create the ViewModel.

XAML Power Toys : add-in for VisualStudio

XAML Power Toys is an extremly useful add-in(build by Karl SHIFFLET) for VisualStudio that you can find at this URL : http://karlshifflett.wordpress.com/xaml-power-toys/. It is also available for Visual Studio 2010 since the 13 February 2010

With this add-in, you just have to make a right-click on you class and configure the viewModel that will be created. Then it copy into the clipboard the code of the corresponding ViewModel. Quite easy :-).

The only drawbacks is that it can be very long to do this for every object and I didn't find a way to automate the operation for a whole library of BusinessObjects...

RightClick : XAMLPowerToysCreateVM
Configuration screen :

v5001viewmodel_thumb

Do you know any other tool performing the same useful things ?



Shout it kick it on DotNetKicks.com




 

MVVM - Creating ViewModel : wrap your business object (solution 1 of n).

24 February 2010

Intro

When you create WPF applications, you may (or you should !) use the M-V-VM pattern and so have to use/create ViewModel. The viewModel job is mainly to expose properties of your businessObjects to your views, ready for binding.

To be ready for the binding the most used solution is to implement INotifyPropertyChanged and to fire events fo every change made. An issue is that you often do not create the business object used by the application which are created by another team and that these object are not ready for binding. So you must find a solution to create an object which will in fact be very similar of your business object BUT ready for binding.

In this serie of post I will try to give some of the solution we can use to do so. A list of all the article is here..

Wrap your business object(solution 1 of n)

The first solution which appears in every developper's brain is to wrap theBusinessObject(BO) into the viewmodel. Every properties of your ViewModel will actually be some kind of proxy to/from the underlying BO.

For example let's take for granted that you have a businessObject like this :

/// <summary>
/// I'am the business object created by another team. I'am not binding-aware : shame on me !
/// </summary>
public class MyBusinessObject
{
  public String LastName { get; set; }
  public String FirstName { get; set; }
  public int Age { get; set; }
  public List<String> FriendsName { get; set; }
}


You will then gives the Business object to your viewModel which will act as a proxy. the result will be something like this :

public class ViewModelWrapped : ViewModelBase
{
private MyBusinessObject _myBusinessObject;
private ObservableCollection<String> _friendsName;
 
public ViewModelWrapped(MyBusinessObject myBusinessObject)
{
  _myBusinessObject = myBusinessObject;
  _friendsName = new ObservableCollection<string>(myBusinessObject.FriendsName);
}
 
public String FirstName
{
  get { return _myBusinessObject.FirstName; }
  set
  {
    FirePropertyChanged("FirstName");
    _myBusinessObject.FirstName = value;
  }
}
 
public String LastName
{
  get { return _myBusinessObject.LastName; }
  set
  {
    FirePropertyChanged("LastName");
    _myBusinessObject.LastName = value;
  }
}
 
public int Age
{
  get { return _myBusinessObject.Age; }
  set
  {
    FirePropertyChanged("Age");
    _myBusinessObject.Age = value;
  }
}
 
public ObservableCollection<String> FriendsName
{
  get { return _friendsName; }
  set
  {
    if (value != null)
    {
      FirePropertyChanged("FriendsName");
      _myBusinessObject.FriendsName = value.ToList<String>();
    }
  }
}
}



Notes : Something interesting to look at is how we wrap our collections to make them bindable : quite a job ! More over the model and the viewModel list are no more synched... The list object itself is synched but the operation on the collection will be made on the viewModel collection and no more on the model collection. In this case adding or removing a friend's name will affect only the ViewModel and not the model.


Pros and cons

Pro :

  • The name of the properties exposed to your views can be differents from those in the business object
  • It's very easy to understand the code when you read it again, even a few months later



Cons:

  • It's a very boring job to re-create the properties of the viewModel to map those from the BO
  • Collection and Set of the model are no more synched with the ViewModel
  • Copy-cut code can leads to error, especially when raising INotifyPropertyChanged events where case matters



NB: I've found an article of Josh Smit on this subject that you may find useful too.
and this link too : MVVM: To Wrap or Not to Wrap? How much should the ViewModel wrap the Model? (Part 1)

Shout it kick it on DotNetKicks.com
 

Use AttachedProperties to add behaviors to the components (Ramora pattern)

19 February 2010

The problem

In WPF you expect your components/controls to behave exactly as you want to.... but this not always the case.
For example : why does this combobox not execute a command when I change the selection or more often why this textbox does not execute a command when I press the Enter (return) key ?

This problem often occurs when you use the - well know - pattern M-V-VM and it's sometimes hard to find a workaround. Today I will explain you a design pattern, know as the Ramora pattern which I find very useful.
By the way, you can also use it to create a library of behaviors for all your projects...

Wanted application

Ramora pattern

One solution (or the ramora pattern explained)


The idea

The solution is based on the attached properties (MSDN page here) of the WPF binding engine. With this mechanism you can attach any property to any object you want and it's massively used in layout controls (DockPanel.Dock for example)..

By attaching and detaching properties we will attach some handlers on the events of our choice to add behaviors to the controls. The value passed by the property will also be useful as a data storage....


The steps are :

  1. Create a class of your choice, no inheritance needed,
  2. Declare an attachedProperty by registering it and adding the corresponding GetXXX and SetXXX,
  3. Add an event handler to the change of this property : inside it, add an event handler to the event you want to catch (for example MouseEnter),
  4. Add the behavior logic inside this last event handler
  5. Attach this behaviors to the aimed control inside your XAML (after you'd declared the XMLNS)


An example

In this example we'll try to add a nice beahavior to any IInputElement : anytime the user presses the 'Enter' key, it will execute a Command.

We'll then declare a Command attached property of type 'ICommand' which will be the command to execute on a given event (very original isnt it ?).

#region Command Property
/// <summary>
/// Enables Command functionality
/// </summary>
public static ICommand GetCommand(DependencyObject obj)
{
	return (ICommand)obj.GetValue(CommandProperty);
}
 
/// <summary>
/// Enables Command functionality
/// </summary>
public static void SetCommand(DependencyObject obj, ICommand value)
{
	obj.SetValue(CommandProperty, value);
}
 
/// <summary>
/// Enables Command functionality
/// </summary>
public static readonly DependencyProperty CommandProperty =
	DependencyProperty.RegisterAttached("Command",
 typeof(ICommand),
 typeof(CommandOnEnter), 
new UIPropertyMetadata(null, new PropertyChangedCallback(CommandPropertyChanged)));



Then everytimes the property is assigned we will attach or detach our event handlers on the DependencyObject which uses it. In our case this is an IInputElement.

/// <summary>
/// Command property changed callback
/// </summary>        
static void CommandPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
	//Test in debug mode if it's binded to the correct type of element...
	Debug.Assert(sender is IInputElement, "Attached property only for a IInputElement");
	if (sender is IInputElement)
	{
		IInputElement inputElement = sender as IInputElement;
 
		// Clean when Command is released
		if (e.OldValue != null)
		{
			Detach(inputElement);
		}
 
		//Attach the behavior
		if (e.NewValue != null)
		{
			Attach(inputElement);
		}
 
	}
}
 
/// <summary>
/// Clean event handlers
/// </summary>
/// <param name="inputElement">The aimed IInputElement</param>
private static void Detach(IInputElement inputElement)
{
	inputElement.PreviewKeyDown -= CommandOnEnter_PreviewKeyDown;
	if (inputElement is FrameworkElement)
		(inputElement as FrameworkElement).Unloaded -= CommandOnEnter_Unloaded;
}
 
 
private static void Attach(IInputElement inputElement)
{
	inputElement.PreviewKeyDown += new KeyEventHandler(CommandOnEnter_PreviewKeyDown);
	if (inputElement is FrameworkElement)
		(inputElement as FrameworkElement).Unloaded += new RoutedEventHandler(CommandOnEnter_Unloaded);
 
}



The keyPressed event handler checks if the enter key is pressed and execute the command if yes. The command to execute is retrieved via the attachedProperties system of WPF (GetValue method) :

static void CommandOnEnter_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
	if (sender is IInputElement)
	{
		var textBox = sender as IInputElement;
		if (e.Key == Key.Enter && e.KeyboardDevice.Modifiers == ModifierKeys.None)
		{
			ICommand cmd = GetCommand(sender as DependencyObject) as ICommand;
			cmd.Execute(null);
		}
 
	}
}



That's all !

Adding a parameter ?

What if you want to pass a parameter to the executed Command ? You will simply have to add another Attached property and get it's value in the keyPressed event handler.

/// <summary>
/// Enables CommandParameter functionality
/// </summary>
public static object GetCommandParameter(DependencyObject obj)
{
	return (object)obj.GetValue(CommandParameterProperty);
}
 
/// <summary>
/// Enables CommandParameter functionality
/// </summary>
public static void SetCommandParameter(DependencyObject obj, object value)
{
	obj.SetValue(CommandParameterProperty, value);
}
 
/// <summary>
/// Enables CommandParameterProperty functionality
/// </summary>
public static readonly DependencyProperty CommandParameterProperty =
	DependencyProperty.RegisterAttached("CommandParameterProperty", typeof(object), typeof(CommandOnEnter));

Funny things to do

The ramora pattern can be used to do a lot of things, here is a list of some I'am thinking :

  • Execute a command on a textbox when pressing enter,
  • Select all the text when a textbox gets the focus,
  • Etc...



Here are some links you may find useful :

  1. Thinking in WPF: attached properties
  2. More advanced attached property use: the Ramora pattern
  3. Behaviors in Silverlight 4.0



Shout it kick it on DotNetKicks.com