• WPF EventSetter Handler Command


    最近做一个工具,突然发现ListBox和ListView等列表控件的MouseDoubleClick事件有时候是获取不到当前双击的行对象数据的,比如这样写:

     <ListBox Grid.Row="1" ItemsSource="{Binding DataList}" 
                     MouseDoubleClick="ListBox_MouseDoubleClick"
                     SelectedItem="{Binding CurrentSelectItem}" Background="AliceBlue">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <DockPanel Height="50"  Background="DarkGray" Width="300">
                            <TextBox Text="{Binding Name}"  Height="30" Width="200" Background="DimGray"></TextBox>
                        </DockPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    View Code
     private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                ListBox listBox = sender as ListBox;
                if (listBox == null || listBox.SelectedItem == null)
                {
                    MessageBox.Show("ListBox1双击对象为空...");
                }
                else
                {
                    var model = listBox.SelectedItem as ListBoxModel;
                    MessageBox.Show("当前对象为" + model.Name + "  " + model.Age);
                }
            }
    View Code

    双击行就会出现双击的对象为空。

    上一篇文章中已经说明怎么解决这个问题:

    http://www.cnblogs.com/ligl/p/5629802.html

    使用Style中的EventSetter Handler这里就不在更多介绍。

    但是今天想要解决的问题是怎么把EventSetter Handler使用Command绑定的方式把Handler事件进行解耦

    要使用第三方类库CommandBehavior(AttachedCommandBehavior acb)进行解耦

    代码如下:

    引用    xmlns:localCommand="clr-namespace:AttachedCommandBehavior"

    <Style x:Key="listBox2Item" TargetType="ListBoxItem">
    <Style.Setters>
    <Setter Property="localCommand:CommandBehavior.Event" Value="MouseDoubleClick"></Setter>
    <Setter Property="localCommand:CommandBehavior.Command" Value="{Binding DataContext.DoubleCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:WinTest}}}"></Setter>
    <Setter Property="localCommand:CommandBehavior.CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
    </Style.Setters>
    </Style>

    ViewModel代码如下

      public class ViewModel : INotifyPropertyChanged
        {
            public ViewModel()
            {
                for (int i = 0; i < 5; i++)
                {
                    DataList.Add(new ListBoxModel() { Name = "张三" + i.ToString(), Age = 1000 + i });
                    DataList2.Add(new ListBoxModel() { Name = "李四" + i.ToString(), Age = 100 + i });
                }
                doubleCommand = new SimpleCommand(obj =>
                {
                    ListBoxItem listBoxItem = obj as ListBoxItem;
                    if (listBoxItem != null)
                    {
                        ListBoxModel model = listBoxItem.Content as ListBoxModel;
                        if (model != null)
                        {
                            CurrentSelectItem2 = model;
                            MessageBox.Show("Command Banding" + model.Name + "  " + model.Age);
                        }
                    }
                    //wpftest.ViewModel
                    MessageBox.Show("Cmd...");
                }, o => true);
            }
    
            public SimpleCommand DoubleCommand
            {
                get
                {
                    return doubleCommand;
                }
    
                set
                {
                    doubleCommand = value;
                    //OnPropertyChanged(new PropertyChangedEventArgs("DoubleCommand"));
                }
            }
    
            private ObservableCollection<ListBoxModel> dataList = new ObservableCollection<ListBoxModel>();
    
            private ObservableCollection<ListBoxModel> _dataList2 = new ObservableCollection<ListBoxModel>();
    
            private ListBoxModel _CurrentSelectItem;
    
            private ListBoxModel _CurrentSelectItem2;
    
            private SimpleCommand doubleCommand;
    
            public ObservableCollection<ListBoxModel> DataList
            {
                get
                {
                    return dataList;
                }
    
                set
                {
                    dataList = value;
                }
            }
    
            /// <summary>
            /// 当前双击的对象
            /// </summary>
            public ListBoxModel CurrentSelectItem
            {
                get
                {
                    return _CurrentSelectItem;
                }
    
                set
                {
                    _CurrentSelectItem = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("CurrentSelectItem"));
                }
            }
    
            /// <summary>
            /// ListBox2双击的对象
            /// </summary>
            public ListBoxModel CurrentSelectItem2
            {
                get
                {
                    return _CurrentSelectItem2;
                }
    
                set
                {
                    _CurrentSelectItem2 = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("CurrentSelectItem2"));
                }
            }
    
            public ObservableCollection<ListBoxModel> DataList2
            {
                get
                {
                    return _dataList2;
                }
    
                set
                {
                    _dataList2 = value;
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, e);
                }
            }
        }
    View Code

    完整Xaml和CS代码如下:

    <Window x:Class="WpfTest.WinTest"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfTest"
            xmlns:localCommand="clr-namespace:AttachedCommandBehavior"
            mc:Ignorable="d"
          Title="WinTest" Height="800" Width="800">
        <Window.Resources>
            <Style TargetType="TextBlock">
                <Style.Setters>
                    <Setter Property="FontSize" Value="20"></Setter>
                </Style.Setters>
            </Style>
    
            <Style  TargetType="Button">
                <Style.Setters>
                    <Setter Property="localCommand:CommandBehavior.Event" Value="MouseDoubleClick"></Setter>
                    <Setter Property="localCommand:CommandBehavior.Command" Value="{Binding DoubleCommand}"></Setter>
                    <Setter Property="localCommand:CommandBehavior.CommandParameter" Value="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:WinTest}}}"></Setter>
                </Style.Setters>
            </Style>
    
            <Style x:Key="listBox2Item" TargetType="ListBoxItem">
                <Style.Setters>
                    <Setter Property="localCommand:CommandBehavior.Event" Value="MouseDoubleClick"></Setter>
                    <Setter Property="localCommand:CommandBehavior.Command" Value="{Binding DataContext.DoubleCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:WinTest}}}"></Setter>
                    <Setter Property="localCommand:CommandBehavior.CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
                </Style.Setters>
            </Style>
            <!--<Style x:Key="listBox2Item" TargetType="ListBoxItem">
                <Style.Setters>
                    <EventSetter Event="MouseDoubleClick" Handler="ListBox2_MouseDoubleClick"></EventSetter>
                </Style.Setters>
            </Style>-->
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal">
                <StackPanel Margin="0 0 20 0">
                    <TextBlock Text="{Binding CurrentSelectItem.Name}"></TextBlock>
                    <TextBlock Text="{Binding CurrentSelectItem.Age}"></TextBlock>
                </StackPanel>
    
                <StackPanel>
                    <TextBlock Text="{Binding CurrentSelectItem2.Name}">
                    </TextBlock>
                    <TextBlock Text="{Binding CurrentSelectItem2.Age}"></TextBlock>
                </StackPanel>
    
                <Button Content="DoubleClick" ></Button>
            </StackPanel>
    
            <ListBox Grid.Row="1" ItemsSource="{Binding DataList}" 
                     MouseDoubleClick="ListBox_MouseDoubleClick"
                     SelectedItem="{Binding CurrentSelectItem}" Background="AliceBlue">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <DockPanel Height="50"  Background="DarkGray" Width="300">
                            <TextBox Text="{Binding Name}"  Height="30" Width="200" Background="DimGray"></TextBox>
                        </DockPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    
            <ListBox Grid.Row="2" ItemsSource="{Binding DataList2}" 
                     SelectedItem="{Binding CurrentSelectItem2}"
                     ItemContainerStyle="{StaticResource listBox2Item}"
                      Background="Silver">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <DockPanel Height="50"  Background="DarkOrange" Width="300">
                            <TextBox Text="{Binding Name}"  Height="30" Width="200" Background="DarkCyan"></TextBox>
                        </DockPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Window>
    View Code
    using AttachedCommandBehavior;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    
    namespace WpfTest
    {
        /// <summary>
        /// WinTest.xaml 的交互逻辑
        /// </summary>
        public partial class WinTest : Window
        {
            ViewModel VModel = new ViewModel();
            public WinTest()
            {
                InitializeComponent();
    
                this.DataContext = VModel;
            }
    
            private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                ListBox listBox = sender as ListBox;
                if (listBox == null || listBox.SelectedItem == null)
                {
                    MessageBox.Show("ListBox1双击对象为空...");
                }
                else
                {
                    var model = listBox.SelectedItem as ListBoxModel;
                    MessageBox.Show("当前对象为" + model.Name + "  " + model.Age);
                }
            }
    
            private void ListBox2_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                ListBoxItem listBoxItem = sender as ListBoxItem;
                if (listBoxItem == null)
                {
                    MessageBox.Show("ListBox2双击对象为空...");
                }
                else
                {
    
                    ListBoxModel model = listBoxItem.Content as ListBoxModel;
                    if (model != null)
                    {
                        VModel.CurrentSelectItem2 = listBoxItem.Content as ListBoxModel;
                        MessageBox.Show(model.Name + "  " + model.Age);
                    }
    
                }
            }
    
        }
    
        public class ViewModel : INotifyPropertyChanged
        {
            public ViewModel()
            {
                for (int i = 0; i < 5; i++)
                {
                    DataList.Add(new ListBoxModel() { Name = "张三" + i.ToString(), Age = 1000 + i });
                    DataList2.Add(new ListBoxModel() { Name = "李四" + i.ToString(), Age = 100 + i });
                }
                doubleCommand = new SimpleCommand(obj =>
                {
                    ListBoxItem listBoxItem = obj as ListBoxItem;
                    if (listBoxItem != null)
                    {
                        ListBoxModel model = listBoxItem.Content as ListBoxModel;
                        if (model != null)
                        {
                            CurrentSelectItem2 = model;
                            MessageBox.Show("Command Banding" + model.Name + "  " + model.Age);
                        }
                    }
                    //wpftest.ViewModel
                    MessageBox.Show("Cmd...");
                }, o => true);
            }
    
            public SimpleCommand DoubleCommand
            {
                get
                {
                    return doubleCommand;
                }
    
                set
                {
                    doubleCommand = value;
                    //OnPropertyChanged(new PropertyChangedEventArgs("DoubleCommand"));
                }
            }
    
            private ObservableCollection<ListBoxModel> dataList = new ObservableCollection<ListBoxModel>();
    
            private ObservableCollection<ListBoxModel> _dataList2 = new ObservableCollection<ListBoxModel>();
    
            private ListBoxModel _CurrentSelectItem;
    
            private ListBoxModel _CurrentSelectItem2;
    
            private SimpleCommand doubleCommand;
    
            public ObservableCollection<ListBoxModel> DataList
            {
                get
                {
                    return dataList;
                }
    
                set
                {
                    dataList = value;
                }
            }
    
            /// <summary>
            /// 当前双击的对象
            /// </summary>
            public ListBoxModel CurrentSelectItem
            {
                get
                {
                    return _CurrentSelectItem;
                }
    
                set
                {
                    _CurrentSelectItem = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("CurrentSelectItem"));
                }
            }
    
            /// <summary>
            /// ListBox2双击的对象
            /// </summary>
            public ListBoxModel CurrentSelectItem2
            {
                get
                {
                    return _CurrentSelectItem2;
                }
    
                set
                {
                    _CurrentSelectItem2 = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("CurrentSelectItem2"));
                }
            }
    
            public ObservableCollection<ListBoxModel> DataList2
            {
                get
                {
                    return _dataList2;
                }
    
                set
                {
                    _dataList2 = value;
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, e);
                }
            }
        }
    
        public class ListBoxModel : INotifyPropertyChanged
        {
            /// <summary>
            /// 姓名
            /// </summary>
            private string _Name;
    
            /// <summary>
            /// 年龄
            /// </summary>
            private int _Age;
    
            public string Name
            {
                get
                {
                    return _Name;
                }
    
                set
                {
                    _Name = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Name"));
                }
            }
    
            public int Age
            {
                get
                {
                    return _Age;
                }
    
                set
                {
                    _Age = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Age"));
                }
            }
    
    
            public void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, e);
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
    View Code

        <Setter Property="localCommand:CommandBehavior.Command" Value="{Binding DataContext.DoubleCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:WinTest}}}"></Setter>

    关于这个Command的Value绑定要使用FindAncestor进行查找才能解决,不然是绑定不到ViewModel中的DoubleCommand

    发个图看看:

    关于CommandBehavior代码可以在

    http://download.csdn.net/download/doncle000/7029327 下载使用

    国外博客http://marlongrech.wordpress.com/2008/12/04/attachedcommandbehavior-aka-acb/

    对于SimpleCommad.cs的源文件我增加了两个参数的构造函数:

     public SimpleCommand(Action<object> execute, Predicate<object> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
                CanExecuteDelegate = canExecute;
                ExecuteDelegate = execute;
            }
    

    源代码下载地址

  • 相关阅读:
    01.网页学习阶段、整站分析、规划
    书签搬运
    如何判断两个链表相交及找到第一个相交点
    Windows平台使用git bash管理github中的工程
    二级指针的操作
    结构体的内存对齐
    大端和小端
    剑指Offer——面试题26:复杂链表的复制
    使用editcap命令将ERF格式转换为pcap格式
    如何在STL的map中使用结构体作为键值
  • 原文地址:https://www.cnblogs.com/ligl/p/5636899.html
Copyright © 2020-2023  润新知