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

2011

2010

2009

2008

Tag - dataBinding

Entries feed - Comments feed

 

How to create your own control library (how-to + tips)

3 October 2010

Reusability and factorizing are maybe the most commons things you want and use when you are developing applications. In WPF it often means creating controls library (i don’t mean UserControl) that will be easy to use in multiple applications.


In this post we'll see all the step to create a control library useable in differents projects.

The example to illustrate the theory will be to create an headered control.

 

PS: note that it already exists in the framework under the nice name of GroupBox.

Creating a control library

Foundation of the project

The first step is to use the VS2010 Wizard named "WPF Custom control library" to create the library which will contain the controls. We will name it, by excess of modesty : “AmazingsWPFControls” !

 

As you can see, VS has created some files and directory for us :

project tree

 

 

Let’s take them one by one ! The “Themes\generic.xaml” file is where the WPF engine, when it loads your control, looks for it’s theme aka. a style setting a template. Here is its content :

<Style TargetType="{x:Type local:CustomControl1}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                <Border Background="{TemplateBinding Background}"
 BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

 

The “AssemblyInfo.cs” file which contains a specific attribute :" ThemeInfo”. It tells the framework where to look for the theme files. Usually it is used like this :

[assembly: ThemeInfo( ResourceDictionaryLocation.None,

//where theme specific resource dictionaries are located //(used if a resource is not found in the page, // or application resource dictionaries) ResourceDictionaryLocation.SourceAssembly

//where the generic resource dictionary is located //(used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )]

 

The “CustomControl1.cs” which is an empty custom control the wizard created for you(how kind of him). Its content is interesting because it show you that you have to override the MetaData of the newly created control to force the WPF engine using the style defined in the generic.xaml file.

public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1),
new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
}

 

 

Each time you want to add a new custom control to the library, you will have to reproduce each of these steps. Of course, the wizard to add a new Custom Control can do it for you but its always a good thing to know how it works. In our case we’ve to rename CustomControl1 to HeaderedControl.

 

Here we are with the foundation of the library. Now we are going to add a template and behaviors to the control.

 

Choose the more appropriated base class

By default the wizard make the control a inherit from the Control class but there are differents options that you may consider for base class :

  • Control : This is a base class which lets you the most freedom but the most to do !
  • ContentControl : This is a good choice if the control will be used to represent a single piece of content.
  • HeaderedContentControl : This is a good choice to represent a single element with an header.
  • ItemsControl: This is a good choice if the control will be used to represent a list of items.

 

 

In our case the best choice should be to inherit from HeaderedContentControl  but we will prefer the ContentControl for demonstration purpose. Note that it meets the specifications: we will represent a single element with an header.

 

Adding a Template and some behaviors to the control

Setting the template of the control

Unlike UserControl there is no code-behind and you set the template of the control by creating a style in the generic.xaml file. This also means that it’s not possible to access the elements via their names because the control and its representation are linked together only at runtime. But don’t worry, you can still access the differents parts following the steps described in this post.

 

 

One of the best practice is to name the revelants parts of your control prefixed with “PART”. By revelants parts, I mean the elements which together build the behavior of your control : for example the track of the slider control is named “PART_Track”. This best practice make your control re-templatable by designer which will know that the controls prefixed by “PART_” are mandatory in the new template they are building. Finally, the parts are declared in the control class via an attribute “TemplatePart” defining the name and the aimed type of control. So in our example, we’ll add a part named “PART_Header which will be the header :

 

/// <summary>
/// A control displaying an header at the top of its content.
/// </summary>    
[TemplatePart(Name = "PART_Header", Type = typeof(Border))]
public class HeaderedControl : Control
{
  // ...
}

 

Adding a content to the control

To add and display a content two things are needed : a property containing the content and a place in the template to display it. The content can be of any type of your choice and is usually placed in the Content property for ContentControl and the Items property for ItemsControl. This is the default behavior but you can override it and tell which property is the content by using the ContentPropertyAttribute on the control’s class :

[ContentPropertyAttribute("Content")] public class HeaderedControl : ContentControl { // ... }

 

Then, in the template, you define where the content is displayed using a ContentPresenter that you can place where you wants depending of the need. We also use a TemplateBinding to bind the content of the class to the ContentPresenter. In our case we add the content under the header :

<Style TargetType="{x:Type local:HeaderedControl}">
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type local:HeaderedControl}">
               <DockPanel>
                   <Border x:Name="PART_Header" DockPanel.Dock="Top" Background="{TemplateBinding Background}"
                           BorderBrush="{TemplateBinding BorderBrush}"
                           BorderThickness="{TemplateBinding BorderThickness}" />
                   <ContentPresenter Content="{TemplateBinding Content}" />
               </DockPanel>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>

 

 

Adding a bindable property to the control

Adding a property to your control is quite useful if you want to permit some customization of its behavior. This is something very common that you use often without noticing it : every attribute you set in the XAML is simply a property of the controls you use.

 

In our case there is a lot which are already here because of our inheritance of FrameworkElement. But let’s said that we want to add another one all we have to do is do declare a new dependency property and its accessor as in the code behind. In our case we add two property : the header (of type Object) and the position of the header in the control. So we have this class :

public class HeaderedControl : ContentControl
{
  static HeaderedControl()
  {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(HeaderedControl),
          new FrameworkPropertyMetadata(typeof(HeaderedControl)));
  }
 
  #region Header
 
  /// <summary>
  /// Header Dependency Property
  /// </summary>
  public static readonly DependencyProperty HeaderProperty =
      DependencyProperty.Register("Header", typeof(object), typeof(HeaderedControl),
          new FrameworkPropertyMetadata((object)null));
 
  /// <summary>
  /// Gets or sets the Header property. This dependency property 
  /// indicates the header to display.
  /// </summary>
  public object Header
  {
      get { return (object)GetValue(HeaderProperty); }
      set { SetValue(HeaderProperty, value); }
  }
 
  #endregion
 
  #region HeaderPosition
 
  /// <summary>
  /// HeaderPosition Dependency Property
  /// </summary>
  public static readonly DependencyProperty HeaderPositionProperty =
      DependencyProperty.Register("HeaderPosition", typeof(HeaderPosition), typeof(HeaderedControl),
          new FrameworkPropertyMetadata(HeaderPosition.Top));
 
  /// <summary>
  /// Gets or sets the HeaderPosition property. This dependency property 
  /// indicates ....
  /// </summary>
  public HeaderPosition HeaderPosition
  {
      get { return (HeaderPosition)GetValue(HeaderPositionProperty); }
      set { SetValue(HeaderPositionProperty, value); }
  }
 
  #endregion
 
 
  /// <summary>
  /// Defines where to place the header
  /// </summary>
  public enum HeaderPosition : int
  {
      /// <summary>
      /// The header is positioned on the left.
      /// </summary>
      Left = 0,
 
      /// <summary>
      /// The header is positioned at the top.
      /// </summary>
      Top = 1,
 
      /// <summary>
      ///  The header is positioned on the right.
      /// </summary>
      Right = 2,
 
      /// <summary>
      ///  The header is positioned at the bottom.
      /// </summary>
      Bottom = 3,
 
  }
}
 

Now let’s use these properties in the template to show and place the header at the right position. We will add another content presenter to display the header and we’ll use a converter to convert the header position into the correct DockPanel.Dock value (only the revelant XAML is showed) :

<ControlTemplate TargetType="{x:Type local:HeaderedControl}">
  <Border Background="{TemplateBinding Background}" 
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}">
      <DockPanel>
          <Border x:Name="PART_Header" 
              DockPanel.Dock="{Binding PositionOfTheHeader,
              RelativeSource={RelativeSource Mode=TemplatedParent},
              Converter={conv:HeaderPositionToDockPositionConverter}}">
              <ContentPresenter Content="{TemplateBinding Header}" />
          </Border>
          <ContentPresenter Content="{TemplateBinding Content}" />
      </DockPanel>
  </Border>
</ControlTemplate>
Adding a custom command to the control

Adding a command to our control is not as straightforward as I thought before to try Smile but here is the guideline is used to make it work fine :

  1. Create the RoutedCommand of your choice in the control class,
  2. Create a private method which will be called when the command is executed,
  3. Register a Class Command binding of this command in the static constructor of the control (you can think of it as a static command binding which will be called each time the command is executed),
  4. In the handler of the class command binding gets the sender of the command, cast it to your class and call the private method you created just before.

 

In our case there no really need of a command but lets say that we will add a command which sets the position of the header property to the “Top” value we will results with this code (against only the revelant part):

static HeaderedControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(HeaderedControl),
   new FrameworkPropertyMetadata(typeof(HeaderedControl)));
 
//Instanciate the command
MoveHeaderToTopCommand = new RoutedUICommand("MoveHeaderToTop",
   "MoveHeaderToTop", typeof(HeaderedControl));
 
//Create the command binding
CommandBinding moveHeaderToTopCommandBinding =
   new CommandBinding(MoveHeaderToTopCommand, 
                  MoveHeaderToTopCommand_Executed,
                  MoveHeaderToTopCommand_CanExecute);
 
CommandManager.
   RegisterClassCommandBinding(typeof(HeaderedControl), 
                     moveHeaderToTopCommandBinding);
}
 
 
static void MoveHeaderToTopCommand_Executed(
        object sender, ExecutedRoutedEventArgs e)
{
    HeaderedControl headeredControl = 
                 sender as HeaderedControl;
    if (headeredControl != null)
       headeredControl.moveHeaderToTop();
}
 
static void MoveHeaderToTopCommand_CanExecute(object sender, 
       CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
 
private void moveHeaderToTop()
{
this.PositionOfTheHeader = HeaderPosition.Top;
}
 

The command is then useable as any other WPF command in your application and you can even use parameters if needed.

 

Adding a Routed event to the control

Adding an event can be useful to notify the others part of your application that an action occurred in the control or to deliver informations.

 

To add an event here are the guideline :

  1. (optionnal) Creates the events args inherithing from RoutedEventArgs that you will use
  2. Declare the event handler of the event,
  3. Declare the RoutedEvent with the name of your choice,
  4. Creates the accesor for a simplier use,
  5. (optionnal) creates a raiseYourEvent method to raise the event easily.

 

 

Now lets assume we wants to raise an event when the header is clicked. For this we’ll subscribe to the Header “MouseDown” event in the OnApplyTemplate() method and raise a newly created event in its handler :

public override void OnApplyTemplate()
{
   base.OnApplyTemplate();
 
   PART_Header = this.GetTemplateChild("PART_Header") as Border;
   if (PART_Header == null)
       throw new ArgumentNullException(
           "Can't find PART_Header in the HeaderedControl template.");
   PART_Header.MouseDown += (a, b) => { RaiseHeaderClickedEvent(); };
}
 
 
/// <summary>
/// the event handler delegate
/// </summary>
public delegate void HeaderClickedEventHandler(object sender, 
    HeaderClickedEventArgs e);
 
/// <summary>
/// Create a custom routed event by first 
/// registering a RoutedEventID
/// This event uses the bubbling routing strategy
/// </summary>
public static readonly RoutedEvent HeaderClickedEvent = 
    EventManager.RegisterRoutedEvent(
   "HeaderClicked", RoutingStrategy.Bubble, 
   typeof(HeaderClickedEventHandler), typeof(HeaderedControl));
 
/// <summary>
/// Occurs when the header is clicked.
/// </summary>
public event RoutedEventHandler HeaderClicked
{
   add { AddHandler(HeaderClickedEvent, value); }
   remove { RemoveHandler(HeaderClickedEvent, value); }
}
 
/// <summary>
/// Raises the header clicked event.
/// </summary>
void RaiseHeaderClickedEvent()
{
   HeaderClickedEventArgs newEventArgs = 
    new HeaderClickedEventArgs(
            HeaderedControl.HeaderClickedEvent);
   RaiseEvent(newEventArgs);
}
 
/// <summary>
/// The header has been clicked event args
/// </summary>
public class HeaderClickedEventArgs : RoutedEventArgs
{
   /// <summary>
   /// Initializes a new instance of the
   /// <see cref="HeaderClickedEventArgs"/> class.
   /// </summary>
   /// <param name="routedEvent">The routed event.</param>
   public HeaderClickedEventArgs(RoutedEvent routedEvent) 
     : base(routedEvent) { }
}

 

 

 

Ease the use of your library by declaring an URL as an XML namespace

 

What is it ? Simply that when you will use the controls in another page you will not declare the XML namespace via an assembly name but via an URL easy to remember. Example :

<Window x:Class="AmazingWPFControls.Showcase.MainWindow"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
 xmlns:controls="http://blog.lexique-du-net.com/wpf/AmazingsWPFControls"
/>


Why to do it ?

So now all you have to do is to create a bright new control Smile

Interesting links



Shout it kick it on DotNetKicks.com

 

Execute a command on a specified control when clicking on a button

16 June 2010

Today another example of the powerful ramora pattern : execute a RoutedCommand on an Control when you click on a button outside of the aimed control scope.

When is it useful ? : for example when you use the infragistics grid (xamdatagrid) and you want to execute the command which remove the selected row from a button outside of the grid. You then have to exectue the DeleteSelectedDataRecords command on the grid from a button which is outside of the scope of the grid ... then this behavior is useful !

Our implementation will also show how we can apply the "Weak Events pattern" with the dependency property trick (attached property / ramora pattern).

And of course this example can be adapted to subscribe on any event you wants and not only the click of a button.

The behavior itself

Our behavior will listen to the click button, and the handling of the click event will execute the routed command on the target element.

public class ExecuteCommandOnControl : DependencyObject
{
  #region Command
 
  /// <summary>
  /// Command Attached Dependency Property
  /// </summary>
  public static readonly DependencyProperty RoutedCommandProperty =
    DependencyProperty.RegisterAttached("RoutedCommand", typeof(RoutedCommand)
	     , typeof(ExecuteCommandOnControl));
 
  /// <summary>
  /// Gets the Command property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static RoutedCommand GetRoutedCommand(DependencyObject d)
  {
    return (RoutedCommand)d.GetValue(RoutedCommandProperty);
  }
 
  /// <summary>
  /// Sets the Command property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static void SetRoutedCommand(DependencyObject d, RoutedCommand value)
  {
    d.SetValue(RoutedCommandProperty, value);
  }
 
  #endregion
 
  #region IInputElement
  /// <summary>
  /// IInputElement Attached Dependency Property
  /// </summary>
  public static readonly DependencyProperty TargetProperty =
    DependencyProperty.RegisterAttached("Target", typeof(IInputElement), 
	   typeof(ExecuteCommandOnControl),
      new FrameworkPropertyMetadata(null,
        new PropertyChangedCallback(OnTargetChanged)));
 
  /// <summary>
  /// Gets the IInputElement property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static IInputElement GetTarget(DependencyObject d)
  {
    return (IInputElement)d.GetValue(TargetProperty);
  }
 
  /// <summary>
  /// Sets the IInputElement property.  This dependency property 
  /// indicates ....
  /// </summary>
  public static void SetTarget(DependencyObject d, IInputElement value)
  {
    d.SetValue(TargetProperty, value);
  }
 
  /// <summary>
  /// Handles changes to the IInputElement property.
  /// </summary>
  private static void OnTargetChanged(DependencyObject d, 
     DependencyPropertyChangedEventArgs e)
  {
    Button button = d as Button;
 
    if (button != null)
    {
      ButtonClickEventManager.AddListener(button, _customEventListener);
 
    } else
    {
      throw 
	  new ArgumentException("This behavior can only be installed on non-null Button !");
    }
  }
 
  #endregion
 
  private static CustomEventListener _customEventListener = new CustomEventListener();
 
}



WeakEvents

So what is the class CustomEventListener ? This is the object which will handle the click on the button. This class implements the interface IWeakEventListener which is a necessary things to use the Weak event pattern.

We will then not subscribe the click event with the usual way ( using the operator +=) but by calling a WeakEventManager of our own : ButtonClickEventManager.

This manager will then keep a weak reference of our listener and the button on which we operate will then be free to be garbage collected. Otherwise, every button on which we subscribe would be keeped in the memory because each one would be connected to our behavior...

Here is the CustomEventListener class :

public class CustomEventListener : IWeakEventListener
{
  #region IWeakEventListener Members
  public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
  {
    if (managerType == typeof(ButtonClickEventManager))
    {
      var target = 
	  ExecuteCommandOnControl.GetTarget(sender as DependencyObject);
      var command = 
	  ExecuteCommandOnControl.GetRoutedCommand(sender as DependencyObject);
 
      if (target == null || command == null) return true;
 
      command.Execute(null, target);
      return true;
    } else
    {
      return false;
    }
  }
  #endregion
}

And here is our WeakEventMAnager :

public class ButtonClickEventManager : WeakEventManager
{
 
  public static void AddListener(Button source, 
       IWeakEventListener listener)
  {
    ButtonClickEventManager.
	   CurrentManager.ProtectedAddListener(source, listener);
  }
 
  public static void RemoveListener(Button source, 
       IWeakEventListener listener)
  {
    ButtonClickEventManager.
	   CurrentManager.ProtectedRemoveListener(source, listener);
  }
 
  protected override void StartListening(object source)
  {
    Button button = (Button)source;
    button.Click += this.OnButtonClick;
  }
 
  protected override void StopListening(object source)
  {
    Button button = (Button)source;
    button.Click -= this.OnButtonClick;
  }
 
  private void OnButtonClick(Object sender, RoutedEventArgs args)
  {
    base.DeliverEvent(sender, args);
  }
 
  private static ButtonClickEventManager CurrentManager
  {
    get
    {
      Type managerType = typeof(ButtonClickEventManager);
      ButtonClickEventManager manager = 
	  (ButtonClickEventManager)WeakEventManager.GetCurrentManager(managerType);
      if (manager == null)
      {
        manager = new ButtonClickEventManager();
        WeakEventManager.SetCurrentManager(managerType, manager);
      }
      return manager;
    }
  }
}



Example of use

Here a little example of how you can use it to launch the deleteSelected command of the infragistics datagrid from a button outside of the grid :

<Button Content="Delete selected"
  tools:ExecuteCommandOnControl.RoutedCommand="{x:Static igDP:DataPresenterCommands.DeleteSelectedDataRecords}"
  tools:ExecuteCommandOnControl.Target="{Binding ElementName=dataGrid}" />
<igDP:XamDataGrid Name="dataGrid" DataSource="{Binding Data}" />



Interesting readings



Shout it kick it on DotNetKicks.com Awaaz Up


 

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


 

Binding on a Property which is not a DependencyProperty

5 April 2010

A lot of controls expose properties which are not DependencyProperties and then you can’t put a binding on it. On some other cases, you only have a getter as accessor and you can’t put a binding on it too…

This is for example the case for the ribbon’s group of the office ribbon or the converter’s parameter.

If you ever tried to do so, you surely had an exception throwned :

A 'Binding' cannot be set on the 'SetCEDEJDED' property of type 'Tralala'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.


In this post we will discover a work-around…

The main idea is to use a kind of proxy/observer (a definition can be found in this post) which will reflect every change on the source object to the target object and vice versa.

Here are the main parts of the solution ..

Specification: the XAML code we'll use

Here is the code snippet which describe how we will use our proxy in the XAML. There will be no code-behind.

<Window x:Class="BindOnNonDependencyProperty.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:us="clr-namespace:BindOnNonDependencyProperty"
    Title="BindOnNonDependencyProperty" >
  <DockPanel >
    <TextBox x:Name="myTextBox" DockPanel.Dock="Top"  />
    <TextBox x:Name="monTextBlockCible"  DockPanel.Dock="Top"  />
    <us:ExtendedBinding Source="{Binding ElementName=myTextBox,Path=Text,Mode=TwoWay}"
              Target="{Binding ElementName=monTextBlockCible,Path=Text,Mode=TwoWay}"
              />
  </DockPanel>
</Window>



The correct base class for our proxy/observer

We will call it ExtendedBinding and it must be inherithing from DependencyObject at last to be abble to own DependencyProperty. But the only way to add a DependencyObject into our XAML is to add it into a resourceDictonary.

This is a drawnback because, by doing it, it will no more be into the control's tree and then it will be impossible to make a binding on one of it's property. Note that it's still possible to use it as a Target from another place in our XAML but you can't do a Binding on one of it's properties. This code will not work :

<Windows.Resources>
   <MyDependencyObject x:Key="myKey" MyProperty="{Binding Tralala, ElementName=myTarget}" />
</Windows.Resources>



Then to put it insode the control's tree, we only had to make it an UIElement will you say... No because in the actual version of the Framework you won't have inheritance of the DataContext and the use of the 'ElementName' binding will be prohibited. Hopefully, there is a solution, our proxy have to inherit from FrameworkElement and everything will work fine !

The DependencyProperties

We will add two dependencyProperties, one will be the target and the second will be the source.

These DP will be customize by using the FrameworkPropertyMetadata two enables these features :

  • Binding will be done using the TwoWay mode,
  • The UpdateSourceTrigger used will be the PropertyChanged event.


How it works

The core of our proxy is to override the DependencyObject's OnPropertyChanged method. Each change on the source or the target will update it's counterparty.

We have to take care not to fall into a loop : when we will update the target or the source we'll also raise a PropertyChanged event and we must ignore this one....


Final code

public class ExtendedBinding : FrameworkElement
  {
    #region Source DP
    //We don't know what will be the Source/target type so we keep 'object'.
    public static readonly DependencyProperty SourceProperty =
      DependencyProperty.Register("Source", typeof(object), typeof(ExtendedBinding),
      new FrameworkPropertyMetadata()
      {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
      });
    public Object Source
    {
      get { return GetValue(ExtendedBinding.SourceProperty); }
      set { SetValue(ExtendedBinding.SourceProperty, value); }
    }
    #endregion
 
    #region Target DP
      //We don't know what will be the Source/target type so we keep 'object'.
    public static readonly DependencyProperty TargetProperty =
      DependencyProperty.Register("Target", typeof(object), typeof(ExtendedBinding),
      new FrameworkPropertyMetadata()
      {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
      });
    public Object Target
    {
      get { return GetValue(ExtendedBinding.TargetProperty); }
      set { SetValue(ExtendedBinding.TargetProperty, value); }
    }
    #endregion
 
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
      base.OnPropertyChanged(e);
      if (e.Property.Name == ExtendedBinding.SourceProperty.Name)
      {
	//no loop wanted
        if (!object.ReferenceEquals(Source, Target))
          Target = Source;
      }
      else if (e.Property.Name == ExtendedBinding.TargetProperty.Name)
      {
	//no loop wanted
        if (!object.ReferenceEquals(Source, Target))
          Source = Target;
      }
    }
 
  }



Shout it kick it on DotNetKicks.com



 

DependencyProperties or INotifyPropertyChanged ?

1 March 2010

When you want to make an object binding-aware you have two choices : implement INotifyPropertyChanged or create DependencyProperties. Which one is the best ? Let's try to answer this question !


How to implement INotifyPropertyChanged

Declaring that your class is implementing INotifyPropertyChanged adds an PropertyChangedEventHandler that you raise for every changes of the properties. We also add a little tricky method checkIfPropertyNameExists(String propertyName) which checks by reflection when debugging if the property name really exists ! You usually ends up with code like this :

/// <summary>
/// Base class for all my viewModel.
/// </summary>
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void FirePropertyChanged(String propertyName)
{
  checkIfPropertyNameExists(propertyName);
  PropertyChangedEventHandler handler = PropertyChanged;
  if (handler != null)
    handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
 
#endregion
 
[Conditional("DEBUG")]
private void checkIfPropertyNameExists(String propertyName)
{
  Type type = this.GetType();
  Debug.Assert(
    type.GetProperty(propertyName) != null,
    propertyName + "property does not exist on object of type : " + type.FullName);
}
}


As you can see, the code is quite easy to write and understand. You have to be very vigilant in checking the name of the property you gives as refactoring do not impacts Strings values but it stays quite simple.

DependencyProperties


MSDN definition of a DependencyProperty (link to) : a property that exists on a DependencyObject, is stored by the DependencyObject property store, and is identified by a DependencyProperty identifier on the owning DependencyObject.

Here is an example of how to create a DependencyProperty :

public class MyDependencyObject : System.Windows.DependencyObject
{
 public static readonly System.Windows.DependencyProperty MyDependencyPropertyProperty =
  System.Windows.DependencyProperty.Register("MyDependencyProperty", typeof(String), typeof(MyDependencyObject));
 
 public String MyDependencyProperty
 {
   get { return (String)GetValue(MyDependencyObject.MyDependencyPropertyProperty); }
   set { SetValue(MyDependencyObject.MyDependencyPropertyProperty, value); }
 }
}



Which one choose ?

Performances

All the tests are done under the .NET framework 4.0 with VisualStudio 2010 and .NET Memory Profiler 3.5.
The tests were already done on this page MVVM – Lambda vs INotifyPropertyChanged vs DependencyObject but I do not get the same results...

Execution times

To tests this I created a simple application and two textblocks binded to two String on my ViewModel. The tests were performed one by one and I took care to remove the inheritance of my ViewModel from DependencyObject when testing the INotifyPropertyChanged.

The code used to tests DependencyProperty is this one :

public static readonly DependencyProperty StringWithDependencyPropertyProperty =
DependencyProperty.Register("StringWithDependencyProperty", typeof(String), typeof(MainViewModel));
public String StringWithDependencyProperty
{
  get { return (String)GetValue(MainViewModel.StringWithDependencyPropertyProperty); }
  set { SetValue(MainViewModel.StringWithDependencyPropertyProperty, value); }
}
...
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++)
  _mainViewModel.StringWithDependencyProperty = i.ToString();
DateTime end = DateTime.Now;
Console.WriteLine("Total time for DependencyProperty : " + (end - start).TotalMilliseconds +" ms.");


The code used to tests INotifyPropertyChangedis this one :

public String StringWithINotifyPropertyChanged
{
 get { return _stringWithINotifyPropertyChanged; }
 set
  {
    _stringWithINotifyPropertyChanged = value;
    firePropertyChanged("StringWithINotifyPropertyChanged");
  }
}
...
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++)
  _mainViewModel.StringWithINotifyPropertyChanged = i.ToString();
DateTime end = DateTime.Now;
Console.WriteLine("Total time for INotifyPropertyChanged : " + (end - start).TotalMilliseconds+" ms.");


The results, for NO binding of the properties, were these :

Total time for DependencyProperty : 45 ms.
Total time for INotifyPropertyChanged : 171 ms.

The results, for one binding of the properties, were these :

Total time for DependencyProperty : 489 ms.
Total time for INotifyPropertyChanged : 1125 ms.

The results, for twelve binding of the properties, were these :

Total time for DependencyProperty : 3600ms.
Total time for INotifyPropertyChanged : 8375 ms.

DPvsInotifyPropertyChangedExecTimeChart
==> DependencyProperty is 2,30 times faster than INotifyPropertyChanged for one binding and this number does not increase with the number of binded controls.!

Edit : as argued in the comments on codeProject and even if it is not the most common way to use INotifyPropertyChanged , I have made the tests with a static event args, and the results are :

Total time for no binding: 154ms
Total time for one binding: 770ms
Total time for twelve bindings: 5605ms

==> DependencyProperies are still better, even if it's less...

Memory usage

I executed the same code and profiled the memory usages :

DependencyProperty created 600 new instances and add 44,583 bytes INotifyPropertyChanged created 876 new instances and add 63,536 bytes

DPvsInotifyPropertyChangedMemoryUsageChart
==> DependencyProperty seems (in my tests) to create less instance and to use less memory than the INotifyPropertyChanged system...

Inheritance issues

To create a DependencyProperty your objects needs to inherit from DependencyObject. This is not always possible and then using INotifyPropertyChanged is the only way to make it Bindable-aware.

Also, by being a DependencyObject, your object will carry with it all the dependency engine stuff and these limitations:


Inheritance from a base class you do not have a grip on ?=> No DependencyProperty !

Animations

Using DependencyProperty make the poperties animatable. If you want to animate a property, there is no simple work-around because, as the MSDN says : In order to be animated, the animation's target property must be a dependency property.

If you can't use DependencyProperty (when you do not create the objects for example), there is still work-arounds techniques.

Flexibility

Using INotifyPropertyChanged is sometimes more flexible than using DependencyProperty. Let me explain that. When you build a screen on which a lot of controls visibility dependsof some rules, you may declare a boolean which value is computed from other boolean.

For example, IsEditionPosible must be set to true only if IsAlreadyInEditionMode = false and if UserHasEditionRights = true. So when changing the value of IsAlreadyInEditionMode or UserHasEditionRights you must tells the binding engine that IsEditionPosible has been updated too. It's easier to do this with INotifyPropertyChanged than with the DependencyProperty with which you should have to create a method, which recalculate and reassign the new value to IsEditionPosible . Here you just have to use this little snippet :

public Boolean IsAlreadyInEditionMode 
{
 get { return _isAlreadyInEditionMode ; }
 set
  {
    _isAlreadyInEditionMode = value;
    firePropertyChanged("IsAlreadyInEditionMode ");
    firePropertyChanged("IsEditionPosible");
  }
}
 
public Boolean UserHasEditionRights 
{
 get { return _userHasEditionRights ; }
 set
  {
    _userHasEditionRights = value;
    firePropertyChanged("UserHasEditionRights");
    firePropertyChanged("IsEditionPosible");
  }
}
 
public Boolean IsEditionPosible
{
 get { return UserHasEditionRights && !IsAlreadyInEditionMode  ; }
}


Note that this is the way that I create computed value for easier binding in my viewModel but this is a subject where improvments may be done...

Flexibility (easier code writing) needed ?=> Choose INotifyPropertyChanged !

Testing

When you performs testing on your object, you will be in trouble if you use DependencyObject : the test are not done on the same thread that created the object and then throws you a "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it".

Testing => No DependencyProperty !

Code Readability/writing

Some people argues that the use of DependencyProperties the code extremely ugly. I myself think that this is exaclty the same. To make easier the creation of dependencyProperty you can use this snippet : link to the snippet


Links of articles on the same subject :



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



 

Use dataBinding and DependencyProperty with a non-WPF or extern object

10 April 2009

Today we are going to learn how we can uses the powerful data binding of WPF even on non-WPF objects.

The problem: when to use this solution ?

Sometimes you need to use the databinding with an object that you have not created and you can't use inheritance.

For example I wanted to use a Mogre Camera and build some WPF animation with it and I couldn't because :

  • WPF animation needed a DependencyProperty to manipulate,
  • I couldn't derive the Mogre.Camera class and add it the correct things because I got the camera from a factory object (the sceneManager).



Then I couldn't use the WPF animation to move my camera... next is how I solve it.

A solution: mine and surely not the best ;-)

Here is the solution i use:

  1. Create a proxy DependencyProperty inside a DependencyObject, for example your main windows.
  2. Override the OnPropertyChanged handler.
  3. Update the aimed attribute inside the handler.


To control my camera, I created this DependencyProperty inside my windows:

public static readonly DependencyProperty CameraPositionProperty = DependencyProperty.Register("CameraPosition", typeof(Point3D), typeof(SurfaceWindow1), new PropertyMetadata(new Point3D(0, 0, 0)));
 
      public Point3D CameraPosition
      {
         get
         {
            return (Point3D)GetValue(CameraPositionProperty);
         }
         set
         {
            SetValue(CameraPositionProperty, value);
         }
      }


Then I added this override :

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
      {
         base.OnPropertyChanged(e);
         if (e.Property.Name.Equals("CameraPosition"))
         {
            _ogre.Camera.SetPosition((float)((Point3D)e.NewValue).X, (float)((Point3D)e.NewValue).Y, (float)((Point3D)e.NewValue).Z);
            _ogre.Camera.LookAt(Vector3.ZERO);
         }
      }



And my usual question :

Does someone have a better idea to perform the same ?