I'm working on a little tool for a project that's based in Silverlight 4 and utilizes the DevExpress Data Grid AgDataGrid control. I really like this grid as it's very easy to work with, style and is feature rich. The app displays a bunch of ads in the grid. When you select an ad the detail view opens as a child window for you to do your editing. Because it allows for multiple row & column selections & because the grid may also contain grouping & summary rows instead of regular data rows (which can be disabled for single row selection), there isn't a simple AgDataGrid.SelectedRow property.
This post is going to first show you how I wrote it to get it working using the standard code-behind event handler approach. Then I'll show you how I changed it to leverage the MVVM Light Toolkit (which I love for Silverlight & Windows Phone 7 apps) and Silverlight behaviors to make the code more manageable and promote more code reuse (as I'm using the grid in other places).
First let me show you the XAML:
Notice the last attribute is wiring up an event handler to the FocusedRowChanged event. The AgDataGrid control does not have a SelectedRow property. Instead it has an event FocusedRowChanged that fires when you change the selected row. Then you use the GetRow() method passing in the FocusedRowHandle to get a reference to the selected row. You then can check the type of the row to see if it is data or not.
Here's what the event handler would look like:
Not so bad. But if you're one of those MVVM disciples (like me), you have this undying urge to get as much out of the code-behind as possible. Plus, this isn't very reusable as I'd have an event handler like this for every grid I implement. Yuck!
Here is where Silverlight behaviors help. If this was a button, I'd much rather use a Silverlight Command. Why? Because commands are separate objects that can be surfaced as properties on your view model and bound to a button in XAML with no code behind. Unfortunately I can't use a command here because commands only work on things that are based on ButtonBase or Hyperlink objects. Instead of using a command I can create a behavior that works in a similar way.
What I did was create a new class (AgDataGridRowSelectedListenerBehavior) that implemented the Behavior class. This is a generic class that I said was based on the AgDataGrid. The behavior has two methods you need to overwrite: OnAttached() and OnDetached(). Basically these are called when you attach the behavior to the control. For me, my implementation wired up an event handler to the grid's FocusedRowChanged event, like so:
Now to wire it up to the grid in XAML, I removed the previous event handler (as well as deleted the handler in code) and added the behavior to the grid's behavior collection:
Nice... no code-behind event handler! And I can easily add this behavior declaratively to other implementations... very nice!
But wait... I said something about the MVVM Light Toolkit. Those familiar with it may have noticed it from the event handler in the behavior. Notice on lines 52 & 54 I'm sending messages around. This messenger is very handy & is just a bit more flexible than event handlers. What I'm doing is sending some message out that says "here's an advertisement that was selected." Now, anything else in my project can register to listen for those things and do something when it sees the message. For instance, in the constructor of my view models for the master & detail views, I register to listen for ads. Here's one of the constructors & the bindable property:
Notice the constructor registers a listener to listen for any ads sent out as messages. When it gets one, it updates the SelectedAd property which uses the whole INotifyPropertyChanged model of alerting the UI that the property changed. Sure, I could update the property directly from the event handler, but then things are tightly coupled, not to mention I'd have to update it twice. This way things are a lot more loose and nimble, which I prefer.