WPF EventSetter Handler Command

Posted ligl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
        }

源代码下载地址

以上是关于WPF EventSetter Handler Command的主要内容,如果未能解决你的问题,请参考以下文章

wpf中如何实现控件的拖拽

求助,WPF如何实现控件的拖动与复制

WPF 早APP.xaml中的style中的按钮事件怎么写

WPF附加事件定义

请教关于WPF上自定义控件添加事件的问题

WPF和Expression Blend开发实例:一个样式实现的数字输入框