在MVVM設計中實現對ListViewItem雙擊事件的響應
阿新 • • 發佈:2021-10-28
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>
-
-
使用附加屬性
-
建立一個附加屬性類
ControlDoubleClick
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)); } } } } }
-
修改
XAML
如下<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>
以上兩種方法都可以實現對
ListViewItem
雙擊事件的繫結。
-