ListView
控件最常用的事件是
SelectionChanged
;如果采用
MVVM
模式来设计 WPF 应用,通常,我们可以使用行为(如
InvokeCommandAction
)并结合命令来实现对该事件的响应;如果我们要实现对
ListViewItem
双击事件的响应——也就是说,双击
ListView
中的某一项——又该怎么做呢?
首先,
ListView
并没有提供相关的事件;其次,
ListViewItem
虽然有
PreviewMouseDoubleClick
(隧道事件),然而在 UI 中,我们却没有适合的方法来调用。那么究竟有没有办法来解决这个问题呢?答案肯定是有,以下便是两种解决方案。第一种是相对简单,在
DataTemplate
中使用
MouseBinding
;第二种方法是通过附加属性,相比第一种略为复杂一些。
- 在
DataTemplate
MouseBinding
-
代码如下ViewModel
public class MainViewModel { public MainViewModel() { Strs = new List<string>(); for (int i = 0; i < 20; i++) { Strs.Add(Guid.NewGuid().ToString("N")); } ListViewDoubleClickCommand = new Command<string>(ListViewDoubleClick); } private void ListViewDoubleClick(string value) { } public List<string> Strs { get; set; } public Command<string> ListViewDoubleClickCommand { get; } }
-
绑定如下XAML
<ListView ItemsSource="{Binding Path=Strs}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"> <TextBlock.InputBindings> <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},Path=DataContext.ListViewDoubleClickCommand}" CommandParameter="{Binding}" /> </TextBlock.InputBindings> </TextBlock> </DataTemplate> </ListView.ItemTemplate> </ListView>
-
- 使用附加属性
-
public class ControlDoubleClick : DependencyObject { public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ControlDoubleClick), new PropertyMetadata(OnCommandChanged)); public static ICommand GetCommand(Control target) { return (ICommand) target.GetValue(CommandProperty); } public static void SetCommand(Control target, ICommand value) { target.SetValue(CommandProperty, value); } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached( "CommandParameter", typeof(object), typeof(ControlDoubleClick), new PropertyMetadata(defaultValue: null)); public static object GetCommandParameter(Control target) { return target.GetValue(CommandParameterProperty); } public static void SetCommandParameter(Control target, object value) { target.SetValue(CommandParameterProperty, value); } private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Control target) { target.PreviewMouseDoubleClick -= Element_PreviewMouseDoubleClick; target.PreviewMouseDoubleClick += Element_PreviewMouseDoubleClick; } } private static void Element_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) { if (sender is Control target) { ICommand command = GetCommand(target); if (command != null) { if (command.CanExecute(GetCommandParameter(target))) { command.Execute(GetCommandParameter(target)); } } } } }
-
<ListView ItemsSource="{Binding Path=Strs}"> <ListView.ItemContainerStyle> <Style TargetType="{x:Type ListViewItem}"> <Setter Property="local:ControlDoubleClick.Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},Path=DataContext.ListViewDoubleClickCommand}" /> <Setter Property="local:ControlDoubleClick.CommandParameter" Value="{Binding}"></Setter> </Style> </ListView.ItemContainerStyle> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView>
-