zoukankan      html  css  js  c++  java
  • Mvvm Light Toolkit for wpf/silverlight系列之Command和Events

    事件是WPF/SL应用程序中UI与后台代码进行交互的最主要方式,与传统方式不同,mvvm中主要通过绑定到命令来进行事件的处理,因此要了解mvvm中处理事件的方式,就必须先熟悉命令的工作原理。 

    一、RelayCommand命令
    WPF/SL命令是通过实现 ICommand 接口创建的。 ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged)。 Execute 执行与命令关联的操作。CanExecute 确定是否可以在当前命令目标上执行命令。在MvvmLight中实现ICommand接口的类是RelayCommand,RelayCommand通过构造函数初始化Execute 和 CanExecute方法,因此,构造函数传入的是委托类型的参数,Execute 和 CanExecute则执行的是委托的方法,RelayCommand相关代码如下:
    [c-sharp:collapse] + expand sourceview plaincopy


    二、 Comand属性绑定
    通常实现了 ICommandSource的控件可以使用Comand属性绑定,实现 ICommandSource 的 WPF 类包括:ButtonBase、MenuItem、Hyperlink 以及 InputBinding。
    简单绑定示例:
    xaml:
    [xhtml] view plaincopy
    <Button Command="{Binding SimpleCommand}" Content="简单命令" /> 

    ViewModel:
    [c-sharp] view plaincopy
    public MainViewModel() 

    ... 

    SimpleCommand = new RelayCommand 

    () => CommandResult = "执行简单命令" 
    ); 

    注意:SL4才开始支持Command属性绑定,之前的版本不能使用Command属性绑定
    CanExecute命令绑定示例:
    xaml:

    [xhtml] view plaincopy
    <Button Command="{Binding CanExecuteCommand}" Content="CanExecute命令" Margin="5,0,5,0"/> 
    <CheckBox x:Name="chkCanClick" IsChecked="{Binding CanClick,Mode=TwoWay}" 
    Content="勾上复选框,CanExecute命令按钮才能变为可用"/> 

    viewmodel:
    [c-sharp] view plaincopy
    bool _CanClick; 
    public bool CanClick 

    get { return _CanClick; } 

    set 

    if (_CanClick == value) 
    return; 

    _CanClick = value; 

    RaisePropertyChanged("CanClick"); 

    // SL中需要手动调用RaiseCanExecuteChanged方法更新按钮可用s状态 
    CanExecuteCommand.RaiseCanExecuteChanged(); 




    public MainViewModel() 

    ... 

    CanExecuteCommand = new RelayCommand 

    () => 

    CommandResult = "执行CanExecute命令"; 
    }, 
    () => CanClick // 等价于()=>{return CanClick;} 
    ); 
    ... 


    与简单命令绑定不同的是,CanExecuteCommand构造函数包含两个参数,第二个参数的返回值表示是否可以在按钮上执行命令操作,返回False,则不能在按钮上执行命令,因此按钮为不可用,返回True,则能够在按钮上执行命令,按钮可用。以上示例中,CanExecute返回值与CheckBox的IsChecked属性关联,这样更改CheckBox的勾选状态,按钮的可用状态会随之更改。

    带参数的命令绑定示例:
    xaml:
    [xhtml] view plaincopy
    <Button Command="{Binding ParamCommand}" Content="带参数的CanExecute命令" 
    CommandParameter="{Binding CanClick,Mode=OneWay}" Margin="5,0,5,0"/> 

    viewmodel:
    [c-sharp] view plaincopy
    public MainViewModel() 

    ... 

    ParamCommand = new RelayCommand<bool?> 

    (p) => 

    CommandResult = string.Format("执行带参数的命令(参数值:{0})", p); 
    }, 
    (p) => p??false 
    ); 
    ... 


    这里ParamCommand接收TextBox的值作为参数,泛型版本表示参数类型为string,此时Execute和CanExecute参数也必须是带参数的版本。

    注意:
    1、在SL4中带参数的CanExecute与不带参数的CanExecute之间的区别;带参数的CanExecute,与参数绑定的属性(CanClick)更改,会自动触发命令的CanExecute方法,而不带参数的CanExecute方法,则需要手动调用CanExecuteCommand.RaiseCanExecuteChanged()方法更新按钮的可用状态。
    2、在WPF中,RelayCommand通过CommandManager不停地侦听按钮的CanExecute的状态,因此WPF中按钮的CanExecute状态会随时响应CanExecute方法中的更改,WPF中可以不调用命令的RaiseCanExecuteChanged方法

    三、使用行为绑定命令
    Command属性绑定只能绑定ICommandSource类型的控件的点击事件,对于其他控件事件,比如TextChanged事件,不能直接绑定到Command,这时我们可以使用Blend的InvokeCommandAction行为来绑定事件到命令,使用步骤如下:
    用Blend4打开解决方案,选中要触发事件的控件,比如TextBox,在资产面板中选择行为,在列表中选择InvokeCommandAction,如图:


    双击InvokeCommandAction后会为TextBox生成InvokeCommandAction行为,在属性栏可以设置行为的属性:

    在EventName栏选择触发的事件名称TextChanged,Command绑定跟Button的绑定方式一样,最后我们生成的代码如下:
    xaml:

    [xhtml] view plaincopy
    <TextBox x:Name="TextBox1" Margin="5,0,5,0" Width="100"> 
    <i:Interaction.Triggers> 
    <i:EventTrigger EventName="TextChanged"> 
    <i:InvokeCommandAction Command="{Binding BehaviourCommand, Mode=OneWay}" 
    CommandParameter="{Binding Text,ElementName=TextBox1}"/> 
    </i:EventTrigger> 
    </i:Interaction.Triggers> 
    </TextBox> 

    ViewModel:
    [c-sharp] view plaincopy
    public MainViewModel() 

    ... 

    BehaviourCommand = new RelayCommand<string> 

    (p) => 

    CommandResult = string.Format("执行TextChanged命令,触发命令的TextBox值为{0}",p); 
    }, 
    (p) => 

    return !string.IsNullOrEmpty(p); 

    ); 
    ... 


    这样就可以间接的将TextBox的MouseRightButtonDown事件绑定到Command。
    注意:
    这种方式相当于将事件映射到Command,CanExecute的返回值只能决定命令是否会被执行,而不能是使得命令目标的可用状态发生改变。以上示例中,输入第一个字母时,命令并没有执行,此时命令无效,但文本框仍然有效,输入第二个字母命令才执行

    四、使用MvvmLight行为EventToCommand绑定命令
    虽然InvokeCommandAction行为可以将控件的事件转换到Command绑定,也可以通过CommandParameter向ViewModel传递参数,但是对于一些特殊的事件,比如MouseMove,我们需要在事件处理方法中得到鼠标位置信息,使用上面的方式仍不能完成任务;这时我们就需要使用EventToCommand行为,它是MvvmLight封装的行为,要使用行为需要添加GalaSoft.MvvmLight.Extras.dll和System.Windows.Interactivity.dll的引用。
    同样,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在列表中选择EventToCommand,双击生成行为,然后设置EventName为MouseMove,然后设置Command绑定,同时需要设置PassEventArgsToCommand="True",也就是将事件参数传递给Command,生成的代码如下:
    xaml:
    [xhtml] view plaincopy
    <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:
    [c-sharp] view plaincopy
    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:
    [xhtml] view plaincopy
    <TextBox x:Name="TextBox2" Text="为空时CanExecute为false" 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代码请在文章最后下载示例代码对照阅读):
    首先,我们创建一个命令参数类型:
    [c-sharp:collapse] + expand sourceview plaincopy

    然后创建行为类:
    [c-sharp:collapse] + expand sourceview plaincopy

    编译生成项目,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在列表中选择MapRoutedEventToCommand ,双击生成行为,然后设置EventName为TextChanged,然后设置Command绑定,代码如下:
    xaml:
    [xhtml] view plaincopy
    <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:
    [c-sharp] view plaincopy
    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; 

    ); 

    这样,我们就可以同时将sender、CommandParameter、和事件参数传递到Command的参数中了

    其他参考链接:

      

    Step by Step Guide to Silverlight 4 Command Binding

    http://www.codeproject.com/Articles/79872/Step-by-Step-Guide-to-Silverlight-4-Command-Bindin

    WPF/Silverlight中的Command

    http://www.cnblogs.com/shanyou/archive/2009/01/17/1377690.html

    本文出处:

    http://www.fengfly.com/plus/view-186773-1.html

  • 相关阅读:
    67. Add Binary
    66. Plus One
    64. Minimum Path Sum
    63. Unique Paths II
    How to skip all the wizard pages and go directly to the installation process?
    Inno Setup打包之先卸载再安装
    How to change the header background color of a QTableView
    Openstack object list 一次最多有一万个 object
    Openstack 的 Log 在 /var/log/syslog 里 【Ubuntu】
    Git 分支
  • 原文地址:https://www.cnblogs.com/bocoimg/p/3222849.html
Copyright © 2011-2022 走看看