2014年1月3日星期五

Mvvm Light Toolkit for WPF/Silverlight系列之Command和Events(2)

这样就可以间接的将TextBoxMouseRightButtonDown事件绑定到Command

注意:
这种方式相当于将事件映射到CommandCanExecute的返回值只能决定命令是否会被执行,而不能是使得命令目标的可用状态发生改变。以上示例中,输入第一个字母时,命令并没有执行,此时命令无效,但文本框仍然有效,输入第二个字母命令才执行
四、使用MvvmLight行为EventToCommand绑定命令
虽然InvokeCommandAction行为可以将控件的事件转换到Command绑定,也可以通过CommandParameterViewModel传递参数,但是对于一些特殊的事件,比如MouseMove,我们需要在事件处理方法中得到鼠标位置信息,使用上面的方式仍不能完成任务;这时我们就需要使用EventToCommand行为,它是MvvmLight封装的行为,要使用行为需要添加GalaSoft.MvvmLight.Extras.dllSystem.Windows.Interactivity.dll的引用。
同样,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在列表中选择EventToCommand,双击生成行为,然后设置EventNameMouseMove,然后设置Command绑定,同时需要设置PassEventArgsToCommand="True",也就是将事件参数传递给Command,生成的代码如下:
xaml:
<Grid>
      <Ellipse Fill="AliceBlue" Height="180" Stroke="Black" Margin="10,8">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="MouseMove">
            <GalaSoft_MvvmLight_Command:EventToCommand PassEventArgsToCommand="True"
                                            Command="{Binding MoveMouseCommand}" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </Ellipse>

      <TextBlock HorizontalAlignment="Center" Text="带事件参数的命令 (鼠标移动事件)"
                 TextWrapping="Wrap" Grid.Row="7" d:LayoutOverrides="Height"
                 Grid.ColumnSpan="2" VerticalAlignment="Center"
                 FontSize="20" FontWeight="Bold"
                 IsHitTestVisible="False" />
    </Grid>

viewmodel:
            MoveMouseCommand = new RelayCommand<MouseEventArgs>
                (
                    (e) => 
                        {
                            var element = e.OriginalSource as UIElement;
                            var point = e.GetPosition(element);

                            CommandResult = string.Format
("执行带MouseEventArgs事件参数的命令,鼠标位置:X-{0}Y-{1}",point.X,point.Y);
                        }
                );

这里命令的初始化方式与带参数的命令一样,只需将参数类型换成事件参数类型
EventToCommand不仅可以用来传递事件参数,他还可以将CanExecute返回值与命令目标的IsEnable属性关联,我们只需将MustToggleIsEnabled的属性设置为True就可以了,示例代码如下:
xaml:
<TextBox x:Name="TextBox2" Text="为空时CanExecutefalse" Margin="5,0,5,0" Width="200">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="TextChanged">
            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding BehaviourCommand}"
                 MustToggleIsEnabled="{Binding IsChecked,ElementName=chkMustToggle}"  
                 CommandParameter="{Binding Text,ElementName=TextBox2}" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </TextBox>
      <CheckBox x:Name="chkMustToggle" IsChecked="False" 
Content="MustToggleIsEnabled,勾选则TextBox的可用状态与CanExecute返回值关联"/>

五、使用自定义行为绑定命令
如果以上方法都不能满足你的要求,你还可以自定义行为来绑定命令,以下是WPF中自定义行为的代码(SL代码请在文章最后下载示例代码对照阅读)
首先,我们创建一个命令参数类型:
using System;
using System.Windows;

namespace MvvmlightCommand.WPF4.TriggerActions
{
    public class EventInformation<TEventArgsType>
    {
        public object Sender { getset; }
        public TEventArgsType EventArgs { getset; }
        public object CommandArgument { getset; }
    }

}

然后创建行为类:
using System;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Input;


namespace MvvmlightCommand.WPF4.TriggerActions
{
    public class MapEventToCommand : MapEventToCommandBase<EventArgs>
    {
    }

    public class MapRoutedEventToCommand : MapEventToCommandBase<RoutedEventArgs>
    {
    }

    public abstract class MapEventToCommandBase<TEventArgsType> : TriggerAction<FrameworkElement>
        where TEventArgsType : EventArgs
    {
        public static readonly DependencyProperty CommandProperty = 
DependencyProperty.Register("Command"typeof(ICommand), 
typeof(MapEventToCommandBase<TEventArgsType>), new PropertyMetadata
(null, OnCommandPropertyChanged));
        public static readonly DependencyProperty 
CommandParameterProperty = DependencyProperty.Register
("CommandParameter"typeof(object), typeof(MapEventToCommandBase<
TEventArgsType>), new PropertyMetadata(null, OnCommandParameterPropertyChanged));

        private static void OnCommandParameterPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var invokeCommand = d as MapEventToCommand;
            if (invokeCommand != null)
            {
                invokeCommand.SetValue(CommandParameterProperty, e.NewValue);
            }
        }

        private static void OnCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var invokeCommand = d as MapEventToCommand;
            if (invokeCommand != null)
            {
                invokeCommand.SetValue(CommandProperty, e.NewValue);
            }
        }

        protected override void Invoke(object parameter)
        {
            if (this.Command == null)
            {
                return;
            }

            var eventInfo = new EventInformation<TEventArgsType>
            {
                EventArgs = parameter as TEventArgsType,
                Sender = this.AssociatedObject,
                CommandArgument = GetValue(CommandParameterProperty)
            };

            if (this.Command.CanExecute(eventInfo))
            {
                this.Command.Execute(eventInfo);
            }
        }

        public ICommand Command
        {
            get
            {
                return (ICommand)base.GetValue(CommandProperty);
            }
            set
            {
                base.SetValue(CommandProperty, value);
            }
        }

        public object CommandParameter
        {
            get
            {
                return base.GetValue(CommandParameterProperty);
            }
            set
            {
                base.SetValue(CommandParameterProperty, value);
            }
        }
    }

}

编译生成项目,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在列表中选择MapRoutedEventToCommand ,双击生成行为,然后设置EventNameTextChanged,然后设置Command绑定,代码如下:
xaml:
      <TextBox x:Name="TextBox3" Text="更改文本框的值" Margin="5,0,5,0" Width="200">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="TextChanged">
            <my:MapRoutedEventToCommand Command="{Binding CustomBehaviorCommand}" 
CommandParameter="P1"/>
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </TextBox>

viewmodel:
            CustomBehaviorCommand = new RelayCommand<EventInformation<RoutedEventArgs>>
               (
                   (ei) =>
                   {
                       EventInformation<RoutedEventArgs> eventInfo = 
ei as EventInformation<RoutedEventArgs>;

                       System.Windows.Controls.TextBox sender = 
eventInfo.Sender as System.Windows.Controls.TextBox;

                       CommandResult = string.Format
("执行{0}TextChanged命令,文本框的值:{1},传递的参数:{2},事件参数:{3}",
                           sender.Name,
                           sender.Text,
                           ei.CommandArgument,
                           ei.EventArgs.GetType().ToString());
                   },
                   (ei) =>
                   {
                       return true;
                   }
               );
这样,我们就可以同时将senderCommandParameter、和事件参数传递到Command的参数中了
本章节主要介绍MvvmLight中命令和事件的处理方法,下章我们将介绍MvvmLight中的Messenger的使用方法,以下是本章源代码下载:
本文来自duanzilin的博客,原文地址:http://blog.csdn.net/duanzilin/archive/2011/05/06/6399640.aspx