20、wpf之MVVM命令绑定

前言:Command可以有效降低前后端的耦合,有利于代码的管理和可读性。前端控件的Command有时可能只是简单的执行一个函数,比如Button。但是借助事件转Command实现MVVM模式的控件,就需要通过Command将EventArgs中相关信息传给ViewModel去解析操作。总之,因为MVVM的模式,ViewModel中不能轻易拿到View中控件的数据,尤其是事件信息。

明确:WPF数据驱动代替传统事件驱动。

目标:MVVM模式下,可以像MVC一样,既能实现前后端数据的分离,又能像View后台程序一样轻松和View中控件进行数据交互。

笔者这里使用Prism去实现Command,不再自己是造轮子,Prism的版本>=8.0

要想实现目标,少不了两个东西,一个是命令,一个是绑定。绑定是基础,命令是实现目标的手段。

一、无参命令

这个比较简单,一般用来演示基本用法。我们这里用Button来测试,虽然用Button不具有代表性(太特殊了,自带Commad这个属性),但是不影响这种简单操作。

<StackPanel VerticalAlignment="Center">
    <TextBox Width="120" Height="30" Text="{Binding NameText}"></TextBox>
    <Button Width="120" Height="30" Command="{Binding ButtonCommand}">按钮</Button>
</StackPanel>

后台

private DelegateCommand buttonCommand;
public DelegateCommand ButtonCommand =>
    buttonCommand ?? (buttonCommand = new DelegateCommand(BtnCmd));

void BtnCmd() { }

很简单,前端点击按钮后,激活这个命令,然后执行命令中的方法BtnCmd();

二、带参命令

2.1 需求

只有继承了ICommandSource接口的控件才会拥有Command依赖属性,基本上只有ButtonBase和MenuItem继承了ICommandSource,所以像Button、RadioButton、CheckBox都有Command属性,但是我们常见的一些TextBox、ComboBox等就没有Command属性。

2.2 需求逻辑

1、View中有些综合控件的数据及变化在MVVM模式下不能被ViewModel知晓,比如DataGrid、ComBox、DatePicker等控件的鼠标及选中变化的事件。

2、这些控件的事件没办法绑定到ViewModel中,只有通过事件转命令实现MVVM模式;

3、事件中是有EventArgs参数,这个参数很重要,其中带有一些事件的数据信息,而我们想要的就是这个EventArgs带有的数据信息,不然我们触发这个事件干什么啊!

这种才是开发中经常会用到的。

2.3 System.Windows.Controls.Primitives.CommandParameter

这是ButtonBase中的CommandParameter属性,如果是使用Microsoft.Xaml.Behaviors程序集中的Interaction实现的事件转Command,这个CommandParameter是在Microsoft.Xaml.Behaviors命名空间下的,其用法没啥区别。

我们先来用Button中的CommandParameter来测下。

<ComboBox Name="cmb" Width="100" Height="40" HorizontalAlignment="Left">
    <ComboBoxItem Content="一" FontSize="18"/>
    <ComboBoxItem Content="二" FontSize="18"/>
    <ComboBoxItem Content="三" FontSize="18"/>
    <ComboBoxItem Content="四" FontSize="18"/>
    <ComboBoxItem Content="五" FontSize="18"/>
    <ComboBoxItem Content="六" FontSize="18"/>
</ComboBox>
<Button Command="{Binding ButtonCommand}" CommandParameter="{Binding ElementName=cmb, Path=SelectedIndex}"/>

ViewModel

private DelegateCommand<int> buttonCommand;
public DelegateCommand<int> ButtonCommand =>
    buttonCommand ?? (buttonCommand = new DelegateCommand<int>(BtnCmd));

void BtnCmd(int selValue)
{
    MessageBox.Show(selValue.ToString());   
}

坑1:

就是说DelegateCommand<T>,这个T不是个object也不是个NUllable,这里就涉及到了数据类型相关知识点了。

问:Int属于Object吗?

答案:不属于

Int是值类型,而Object是引用类型。 把DelegateCommand<T>中的T换成string就没啥问题。

这里修改下,将Int换成Object,就可以了。

这里通过CommandParameter绑定了ComboBox控件的SelectedIndex属性,然后后台需要使用DelegateCommand的泛型函数,这个泛型上面也看到了,需要是Object类型的。最后这个命令执行的函数对应的也需要参数,这里就像事件函数一样了,不同的是,事件函数中一般有两个参数,一个是sender,一个是EventArgs(或其他事件参数),需要对这两个参数进行操作,从里面提取出我们需要的,但这里,我们通过绑定,已经很明确的知道了我们想要的事件参数中的数据是什么,直接操作这个通过绑定传递进来的数据就可以了。一个是在后台去提取需要参数,一个是在前端写好需要的参数并传递给后台。

2.4 Microsoft.Xaml.Behaviors. CommandParameter

使用方法和上面是一样的,这里通过Interaction来实现Command。使用HandyControl中的DatePicker控件演示。

<hc:DatePicker x:Name="startDpEventDate" ShowClearButton="True" Margin="2"
    SelectedDate="{x:Static system:DateTime.Now}" 
    Width="230" Height="40"
    hc:InfoElement.TitleWidth="85"
    hc:InfoElement.TitlePlacement="Left"
    hc:InfoElement.Title="开始时间"
    FontSize="18">
    <bh:Interaction.Triggers>
        <bh:EventTrigger EventName="SelectedDateChanged">
            <bh:InvokeCommandAction Command="{Binding StartDatePickerCmd}"
                                    CommandParameter="{Binding ElementName=startDpEventDate, Path=SelectedDate}"/>
        </bh:EventTrigger>
    </bh:Interaction.Triggers>
</hc:DatePicker>

后台和上个差不多,不同的是针对不同控件的不同属性做出的操作。这里绑定的控件是自己(其实还有其他方式,Binding的相关知识,见参考文献3.7中有用到),属性是SelectedDate。

void StartDatePicker(object startTime)
{
    string s = startTime.ToString();
    MessageBox.Show(s);
}

同理,其他控件比如DataGrid,其选中改变事件等都可以通过此方法实现MVVM操作。

当然,也可以同时写多个命令,见参考文献3.3。同时通过修改列表控件的数据模板,可以实现列表控件的item项的Command功能,见参考文献3.4。

三、引用文献

3.1 Wpf MVVM——命令绑定和消息发送_weixin_44538156的博客-CSDN博客

3.2 自定义InvokeMouseCommandAction类,用于WPF中的鼠标事件到prism:DelegateCommand的绑定_jiuzaizuotian2014的博客-CSDN博客

3.3 MVVM中轻松实现Command绑定(三)任意事件的Command - cw_volcano - 博客园

3.4 WPF: 在 MVVM 设计中实现对 ListViewItem 双击事件的响应 - WPInfo - 博客园

3.5 Prism8.0(二):数据绑定与命令_碎碎念的安静的博客-CSDN博客_prism 属性绑定

3.6 Introduction to Prism | Prism

3.7 wpf 如何将参数通过CommandParameter 传入viewmodel_老程序猿一枚的博客-CSDN博客 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值