In a WPF application using MVVM, I have a usercontrol with a listview item. In run time, it will use databinding to fill the listview with a collection of objects.
What is the correct way to attach a double click event to the items in the listview so that when an item in the list view is doubleclicked, A corresponding event in the view model is fired and has a reference to the item clicked?
How can it be done in a clean MVVM way i.e. no code behind in the View?
I realize that this discussion is a year old, but with .NET 4, are there any thoughts on this solution? I absolutely agree that the point of MVVM is NOT to eliminate a code behind file. I also feel very strongly that just because something is complicated, doesn't mean it's better. Here is what I put in the code behind:
I like to use Attached Command Behaviors and Commands. Marlon Grech has a very good implementation of the Attached Command Behaviors. Using these, we could then assign a style to the ListView's ItemContainerStyle property that will set the command for each ListViewItem.
Here we set the command to be fired on the MouseDoubleClick event, and the CommandParameter, will be the data object that we click on. Here I'm traveling up the visual tree to get the command that I'm using, but you could just as easily create application wide commands.
For the commands, you can either implement an ICommand directly, or use some of the helpers like those that come in the MVVM Toolkit.
I am finding it simpler to link the command when the view is created:
In my case
BindAndShow
looks like this (updatecontrols+avalondock):Though the approach should work with whatever method you have of opening new views.
I have found a very easy and clean way to do this with the Blend SDK Event triggers. Clean MVVM, reusable and no code-behind.
You probably already have something like this:
Now include a ControlTemplate for the ListViewItem like this if you don't already use one:
The GridViewRowPresenter will be the visual root of all elements "inside" making up a list row element. Now we could insert a trigger there to look for MouseDoubleClick routed events and call a command via InvokeCommandAction like this:
If you have visual elements "above" the GridRowPresenter (probalby starting with a grid) you can also put the Trigger there.
Unfortunately MouseDoubleClick events are not generated from every visual element (they are from Controls, but not from FrameworkElements for example). A workaround is to derive a class from EventTrigger and look for MouseButtonEventArgs with a ClickCount of 2. This effectively filters out all non-MouseButtonEvents and all MoseButtonEvents with a ClickCount != 2.
Now we can write this ('h' is the Namespace of the helper class above):
You can use Caliburn's Action feature to map events to methods on your ViewModel. Assuming you have an
ItemActivated
method on yourViewModel
, then corresponding XAML would look like:For further details you can examine Caliburn's documentation and samples.
I am able to get this to work with .NET 4.5. Seems straight forward and no third party or code behind needed.