Fun with Attached Dependency Properties – Part 1 - Attached Commands

I have been working with XAML and the Dependency Property system for about 3 years now and I have decided to start sharing some of the fun stuff that I do that I personally find to be really cool, useful, or just a massive time savings vs doing it some other way. I will be doing several blog posts along these lines in the next few weeks. This is the first one of many to come.

First up I want to show you a really useful little trick to get a command to work with almost anything. All the time I hear people say well I need to put in some code behind because I want to handle event x on some item and I can’t add a command to it or it doesn’t have one and I have no idea how to make one. Well the first thing that I am going to share in this blog post is how to accomplish handling any event and invoking a command. Let’s take a look at our sample.

<UserControl 
    x:Class="Infragistics.XamlTricks.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Infragistics.XamlTricks">
    <UserControl.Resources>
        <DataTemplate x:Key="ListBoxItemTemplate">
            <TextBlock Text="{Binding DisplayName}" />
        </DataTemplate>
    </UserControl.Resources>
        <Grid x:Name="LayoutRoot">
        <Grid.DataContext>
            <local:ViewModel />
        </Grid.DataContext>
        <ItemsControl 
            ItemsSource="{Binding ListBoxItems, Mode=OneWay}" 
            ItemTemplate="{StaticResource ListBoxItemTemplate}"/>
    </Grid>
</UserControl>

You can see that we have an items control that is bound to the collection ListBoxItems that lives off of our view model. We have some functionality requirement for our application hat makes us have to be able to click any item in the ItemsControl and take some action. But wait there is more we also have to know what ItemsControl the item came from and we want to link the click up to a single command that is able to tell which ItemsControl the item is from. Surely we must use a bit of code behind to do this right? NO, I am about to provide you with a simple class that will allow you to add this to your xaml with one attached dependency property as follows:

<ItemsControl 
            Grid.Column="1" 
            ItemsSource="{Binding ListBoxItems, Mode=OneWay}" 
            local:MouseDownCommandHelper.MouseDownCommand="{Binding Path=DataContext.ListItemClickedCommand,ElementName=LayoutRoot}"
            ItemTemplate="{StaticResource ListBoxItemTemplate}"/>

So our ItemsControl XAML now has an attached dependency property called the MouseDownCommandHelper.MouseDownCommand which is bound to a command that is a property of whatever object that is currently our DataContext for the LayoutRoot. If we look at our sample we can see that the DataContext for LayoutRoot is our ViewModel. Now all we have to do is click any item that lives under the ItemsControl in the visual tree and we will invoke the command that we are bound to. You can also if you want to be more restrictive in what you have to click on to invoke the command by putting the command on the TextBlock from the template. To accomplish this in our MouseDownCommandHelper clas we have a PropertyChangedCallback for the MouseDownCommand dependency property that looks like this:

private static void MouseDownCommandProperty_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    FrameworkElement el = obj as FrameworkElement;
    el.Unloaded += el_Unloaded;
    el.MouseLeftButtonDown += el_MouseLeftButtonDown;
}

You can see that we are attaching event handlers for both Unloaded and MouseLeftButtonDown lets take a look at the handler for MouseLeftButtonDown

static void el_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
  ICommand command = (sender as DependencyObject).GetValue(MouseDownCommandHelper.MouseDownCommandProperty) as ICommand;
  if (command != null)
  {
      CommandArgument argument = new CommandArgument(sender, e);
      if (command.CanExecute(argument))
      {
          command.Execute(argument);
      }
  }
}

And for the sake of cleaning up after ourselves we in the unloaded even detach both event handlers so that the object can be garbage collected when it is time. I hope that you can see how useful that this will be and to give you something to play with I have attached a sample project that demonstrates how this works.


Add a Comment

Be the first one to add a comment. Please Login or Register to add comment.