If you are building a WPF application, chances are you are using the MVVM pattern. If you are using the MVVM pattern, I am sure you have discovered certain scenarios that become difficult to accomplish in a ViewModel when trying to respond to something in the View. If you are building a WPF application, using MVVM, and using the Infragistics XamDataPresenter family of controls, then this post if for you. Actually, if you are just using MVVM in any XAML application, this post is for you.
One of the most common hurdles for dealing with controls in a View from within a ViewModel is the limitation of events. Yes, those tightly coupling mechanisms for responding to a control’s actions. Well, in this post I will show you how to crate an attached property that will allow you to attach any command to any control for an event of your choosing. Now I know what you’re thinking, “but Brian, I can already do this with a behavior”. Yeah, but I don’t like using Microsoft.Expression.Interactivity in my apps. Plus this is a good exercise to learn how to create an attached property.
The scenario I am going to cover is as follows: I have a XamDataPresenter populated with some important data. When a user double clicks on a row in the grid I want to act on the selected item in a ViewModel.
Here is our View (DataContext set to our ViewModel):
Let’s take a look at our ViewModel.
As you can see, we are not dealing with anything complicated here. We have a XamDataPresenter data bound to a collection of Person objects. Our ViewModel has an ICommand defined in the form of a DelegateCommand, also known as a RelayCommand. When this command executes, we simply display the object being clicked on which is passed as a parameter to the command.
Now, how do we hook our command up to the XamDataPresenter.DoubleClick event? Enter our attached property. Start by creating a class named XamDataPresenter. Then add the following code.
As you can see, the syntax for an attached property is very similar to a dependency property. But notice the syntactical differences. We are using the DependencyProperty.RegisterAttached method and then providing the common parameters. The name of the property, the type of the property, the owner of the property, and of course our meta data about the property. In this case we added a null default value and provided a property changed callback.
I am not going to go into all the specifics of attach properties. For that information read this. What we are going to concentrate on is hooking into our DoubleClick event and executing our command. So let’s add some code to our property changed callback handler.
When the value of our attached property is assigned, this callback handler will execute. This allows us to get the instance of the element, in this case the XamDataPresenter. Once we have the instance we can hook into it’s MouseDoubleClick event. Then we get the command assigned to the element, get it’s paramter (we will implement this in a minute), and then execute the command. As you can see you use the DependencyObject.GetValue to retrieve the attached property’s value.
Now that we have a command, let’s add the CommandParameter.
Now we can go back to our OnDoubleClickCommandChange callback handler and implement our command parameter.
The last thing to do is to attach our properties to our XamDataPresenter and set their values. This is what our view should look like now.
Notice how we are using an xmlns namespace that has been declared at the top of our view. We are binding the Command property to the DoubleClickCommand that is defined in our ViewModel and we are binding the CommandParameter to the ActiveDataItem (SelectedItem) of the XamDataPresenter.
Now run the application and double click on a row:
The Best Part about it is that this will work the same way no matter what type of view you are using in your XamDataPresenter.
And yes, this will even work for the XamDataGrid because it derives from XamDataPresenter. Hopefully you can start to see how you can leverage attached properties in your application to extend Infragistics controls to make them more MVVM friendly. For example, you could use this same approach to expose a SelectedItems property to store multiple selected rows in a ViewModel. Hmm… Maybe I will just blog about that too.