tags:

views:

6246

answers:

5

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?

+15  A: 

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.

<Style x:Key="Local_OpenEntityStyle"
    TargetType="{x:Type ListViewItem}">
 <Setter Property="acb:CommandBehavior.Event"
   Value="MouseDoubleClick" />
 <Setter Property="acb:CommandBehavior.Command"
   Value="{Binding ElementName=uiEntityListDisplay, Path=DataContext.OpenEntityCommand}" />
 <Setter Property="acb:CommandBehavior.CommandParameter"
   Value="{Binding}" />
</Style>

For the commands, you can either implement an ICommand directly, or use some of the helpers like those that come in the MVVM Toolkit.

rmoore
+1 I've found this to be my preferred solution when working with Composite Application Guidance for WPF (Prism).
Travis Heseman
@rmoore: What does the namespace 'acb:' stand for in your code sampleabove?
Nam Gi VU
A: 

You can use Caliburn's Action feature to map events to methods on your ViewModel. Assuming you have an ItemActivated method on your ViewModel, then corresponding XAML would look like:

<ListView x:Name="list" 
   Message.Attach="[Event MouseDoubleClick] = [Action ItemActivated(list.SelectedItem)]" >

For further details you can examine Caliburn's documentation and samples.

idursun
A: 

I use Marlon Grech's solution as well. The primary problem with it is you don't get the automatic message cracking you get when you use normal code behind. For instance, for a mouse click, you don't get the point where the click took place passed to you automatically.

+15  A: 

Please, code behind is not a bad thing at all. Unfortunately, quite a lot people in the WPF community got this wrong.

MVVM is not a pattern to eliminate the code behind. It is to separate the view part (appearance, animations, etc.) from the logic part (workflow). Furthermore, you are able to unit test the logic part.

I know enough scenarios where you have to write code behind because data binding is not a solution to everything. In your scenario I would handle the DoubleClick event in the code behind file and delegate this call to the ViewModel.

Sample applications that use code behind and still fulfill the MVVM separation can be found here:

WPF Application Framework (WAF) - http://waf.codeplex.com

jbe
Well said, I refuse to use all that code and an extra DLL just to do a double-click!
Eduardo Molteni
This only use Binding thing is giving me a real headache. It's like being asked to code with 1 arm, 1 eye on an eye patch, and standing on 1 leg. Double click should be simple, and I don't see how all this additional code is worth it.
Echiban
@jbe: I'm afraid I do not totally agree with you. If you say 'code behind is not bad', then I have a question about that: Why don't we delegate the click event for button but often using the binding (using Command property) instead?
Nam Gi VU
@Nam Gi VU: I would always prefer a Command Binding when it is supported by the WPF Control. A Command Binding does more than just relaying the ‘Click’ event to the ViewModel (e.g. CanExecute). But Commands are only available for the most common scenarios. For other scenarios we can use the code-behind file and there we delegate non-UI related concerns to the ViewModel or the Model.
jbe
@jbe: Now I understand you more! Nice discussion with you!
Nam Gi VU
+1  A: 

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:

    private void ButtonClick(object sender, RoutedEventArgs e)
    {
        dynamic viewModel = DataContext;
        viewModel.ButtonClick(sender, e);
    }
Aaron