How to bind mousedouble click command in mvvm

2019-01-17 21:35发布

I have listview and I want to have show new window when someone double click in any position. But I have mvvm application and I don't want to have any function in code behind of xaml file, like this: How to bind a Command to double-click on a row in DataGrid and many other samples like this. I want to have method in viewmodel file and bind it like this:

<ListView ... MouseDoubleClick="{Binding myfunction}"> 

Thanks

标签: c# wpf mvvm
3条回答
做自己的国王
2楼-- · 2019-01-17 21:44

This is a working example of a method to trigger a command (In the ViewModel) based on the clicked item in a list. The command in the ViewModel will get the "clicked" item as its parameter.

I'm using the Textblock.InputBindings and that might be part of the Blend SDK linked by Blachshma, but you will not need any other DLLs for this to work.

In my example the ViewModel is bound to the DataContext of the UserControl, that is why I need to use the RelativeSource FindAncestor to find the ViewModel from my TextBlock.

Edit: Fixed the width problem by binding the Width of the TextBlock to the ActualWidth of the ListBox.

Just one problem, the double click will only work when you click inside the text in the textblock even if the list itself is much wider.

    <ListView ItemsSource="{Binding Model.TablesView}"   Grid.Row="1" 
              SelectedItem="{Binding Model.SelectedTable, Mode=TwoWay}"  >
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=.}" 
                   Width="{Binding Path=ActualWidth, 
                             RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" >
                    <TextBlock.InputBindings>
                        <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding DataContext.MoveItemRightCommand,
                                        RelativeSource={RelativeSource FindAncestor, 
                                        AncestorType={x:Type UserControl}}}"
                                      CommandParameter="{Binding .}"/>
                    </TextBlock.InputBindings>
                </TextBlock>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
查看更多
不美不萌又怎样
3楼-- · 2019-01-17 21:51

The easiest way to do this is to use System.Windows.Interactivity and Microsoft.Expression.Interactions (both freely available through the Blend SDK)

So start by adding the following namespaces to your view

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

Next, catch the DoubleClick event and pass it to the command:

<ListView ..... >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDoubleClick">
            <local:EventToCommand Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.myfunction}" />
         </i:EventTrigger
    </i:Interaction.Triggers>
</ListView>

Note: The EventToCommand used is the one from the MVVM Light Toolkit and can be downloaded here. What it does is execute the command (myFunction) as soon as the event is triggered.

This is based on the assumption that the myFunction command is in the DataContext which the ListView users. Otherwise, modify the binding of the EventToCommand to wherever the command is.

查看更多
聊天终结者
4楼-- · 2019-01-17 21:54

You can use Attached Properties to bind any event you want.

For MouseDoubleClick:

namespace Behavior
{
public class MouseDoubleClick
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command",
        typeof(ICommand),
        typeof(MouseDoubleClick),
        new UIPropertyMetadata(CommandChanged));

    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.RegisterAttached("CommandParameter",
                                            typeof(object),
                                            typeof(MouseDoubleClick),
                                            new UIPropertyMetadata(null));

    public static void SetCommand(DependencyObject target, ICommand value)
    {
        target.SetValue(CommandProperty, value);
    }

    public static void SetCommandParameter(DependencyObject target, object value)
    {
        target.SetValue(CommandParameterProperty, value);
    }
    public static object GetCommandParameter(DependencyObject target)
    {
        return target.GetValue(CommandParameterProperty);
    }
    private static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        Control control = target as Control;
        if (control != null)
        {
            if ((e.NewValue != null) && (e.OldValue == null))
            {
                control.MouseDoubleClick += OnMouseDoubleClick;
            }
            else if ((e.NewValue == null) && (e.OldValue != null))
            {
                control.MouseDoubleClick -= OnMouseDoubleClick;
            }
        }
    }
    private static void OnMouseDoubleClick(object sender, RoutedEventArgs e)
    {
        Control control = sender as Control;
        ICommand command = (ICommand)control.GetValue(CommandProperty);
        object commandParameter = control.GetValue(CommandParameterProperty);
        command.Execute(commandParameter);
    }
}
}

And in Xaml:

 <ListBox Behavior:MouseDoubleClick.Command="{Binding ....}"
          Behavior:MouseDoubleClick.CommandParameter="{Binding ....}"/>
查看更多
登录 后发表回答