wpfmvvm从入门到精通4:命令和事件(代码片段)

lonelyxmas lonelyxmas     2023-03-13     243

关键词:

原文:WPF MVVM从入门到精通4:命令和事件

?

WPF MVVM从入门到精通1:MVVM模式简介

WPF MVVM从入门到精通2:实现一个登录窗口

WPF MVVM从入门到精通3:数据绑定

WPF MVVM从入门到精通4:命令和事件

WPF MVVM从入门到精通5:PasswordBox的绑定

WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定

WPF MVVM从入门到精通7:关闭窗口和打开新窗口

WPF MVVM从入门到精通8:数据验证

完整示例代码下载LoginDemo

?

这一部分我们要做的事情,是把点击登录按钮的事件也在ViewModel里实现。若不是用MVVM模式,可能XAML文件里是这样的:

<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Width="200" Height="30" Click="Button_Click"/>

而跟XAML文件相关的CS文件里则是这样的:

private void Button_Click(object sender, RoutedEventArgs e)

    //业务处理逻辑代码

如此一来,前端和后端的代码又耦合在一起了。其实,命令和事件都是可以绑定的,就像数据一样。

我们先来了解一下命令。ICommand是所有命令的接口,它主要完成两件事情,这个命令能否被执行,以及执行命令。

event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter);
public void Execute(object parameter);

例如当用户名为空时,我们可能会禁用按钮。当登录按钮跟一个命令绑定在一起时,CanExecute会不断被执行,如果返回false,按钮的IsEnabled属性也会被置为false。

一般情况下,我们需要继承ICommand接口来进行开发。

using System;
using System.Windows.Input;

namespace LoginDemo.ViewModel.Common

    /// <summary>
    /// 命令基类
    /// </summary>
    public class BaseCommand : ICommand
    
        public event EventHandler CanExecuteChanged
        
            add
            
                if (_canExecute != null)
                
                    CommandManager.RequerySuggested += value;
                
            
            remove
            
                if (_canExecute != null)
                
                    CommandManager.RequerySuggested -= value;
                
            
        

        public bool CanExecute(object parameter)
        
            if (_canExecute == null)
            
                return true;
            
            return _canExecute(parameter);
        

        public void Execute(object parameter)
        
            if (_execute != null && CanExecute(parameter))
            
                _execute(parameter);
            
        

        private Func<object, bool> _canExecute;
        private Action<object> _execute;

        public BaseCommand(Action<object> execute, Func<object, bool> canExecute)
        
            _execute = execute;
            _canExecute = canExecute;
        

        public BaseCommand(Action<object> execute) :
            this(execute, null)
        
        
    

BaseCommand的功能很简单,就是执行命令前先判断一下命令能不能执行。

然后我们就可以绑定命令了,在后端这样写:

private BaseCommand clickLoginCommand;
public BaseCommand ClickLoginCommand

    get
    
        if(clickLoginCommand==null)
        
            clickLoginCommand = new BaseCommand(new Action<object>(o =>
            
                //执行登录逻辑
            ));
        
        return clickLoginCommand;
    

前端这样写:

<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Width="200" Height="30" Command="Binding ClickLoginCommand"/>

点击按钮执行登录逻辑的代码就这样完成了。但不要急着复制代码,因为我们不打算使用命令。

我们知道,对于按钮的操作,不一定是点击,可能是鼠标划过,可能是鼠标右击。那Command触发的是什么呢?就是点击,没有其他了。对于其他控件,例如是输入框,Command又代表什么呢?文本改变事件能用Command吗?这些问题让我们感到困惑,所以一般在项目中,我都只会使用事件,而不会使用命令(即使是单击事件)。

BaseCommand这个类还可以留着,我们后面还需要使用的。在引入事件之前,我们需要先引用一个dll:System.Windows.Interactivity.dll。这个dll并不是.NET Framework的标配,它是Blend的一个类库。可以在扩展的程序集里找到:

技术图片

如果没有找到(我安装VS2017后就没有找到),需要安装以下库才有:

技术图片

好了,引用了System.Windows.Interactivity.dll后,我们就可以开始讲事件了。

有些事件是有参数的,例如鼠标移动这个事件,会带上鼠标的位置。但我们之前使用的命令,默认传入的参数是null。为了能够传递参数,我们需要先定义一个事件基类:

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace LoginDemo.ViewModel.Common

    /// <summary>
    /// 事件命令
    /// </summary>
    public class EventCommand : TriggerAction<DependencyObject>
    
        protected override void Invoke(object parameter)
        
            if (CommandParameter != null)
            
                parameter = CommandParameter;
            
            if (Command != null)
            
                Command.Execute(parameter);
            
        

        /// <summary>
        /// 事件
        /// </summary>
        public ICommand Command
        
            get  return (ICommand)GetValue(CommandProperty); 
            set  SetValue(CommandProperty, value); 
        
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null));

        /// <summary>
        /// 事件参数,如果为空,将自动传入事件的真实参数
        /// </summary>
        public object CommandParameter
        
            get  return (object)GetValue(CommandParameterProperty); 
            set  SetValue(CommandParameterProperty, value); 
        
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommand), new PropertyMetadata(null));
    

现在,我们可以在ViewModel里增加如下代码:

private BaseCommand loginClick;
/// <summary>
/// 登录事件
/// </summary>
public BaseCommand LoginClick

    get
    
        if(loginClick==null)
        
            loginClick = new BaseCommand(new Action<object>(o =>
            
                //执行登录逻辑
            ));
        
        return loginClick;
                

然后在XAML文件里,先加入i这个命名空间:xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity",然后修改按钮的代码:

<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Width="200" Height="30">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <c:EventCommand Command="Binding LoginClick"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

上面的代码指出,Click这个事件,绑定到了LoginClick这个属性。当我们点击按钮的时候,LoginClick里面的Action就会被执行。

wpfmvvm从入门到精通6:radiobutton等一对多控件的绑定(代码片段)

原文:WPFMVVM从入门到精通6:RadioButton等一对多控件的绑定 ?WPFMVVM从入门到精通1:MVVM模式简介WPFMVVM从入门到精通2:实现一个登录窗口WPFMVVM从入门到精通3:数据绑定WPFMVVM从入门到精通4:命令和事件WPFMVVM从入门到... 查看详情

wpfmvvm从入门到精通4:命令和事件

这一部分我们要做的事情,是把点击登录按钮的事件也在ViewModel里实现。若不是用MVVM模式,可能XAML文件里是这样的:<ButtonGrid.Row="3"Grid.ColumnSpan="2"Content="登录"Width="200"Height="30"Click="Button_Click"/>而跟XAML文件相关的CS文件里则... 查看详情

wpfmvvm从入门到精通3:数据绑定

原文:WPFMVVM从入门到精通3:数据绑定 ?WPFMVVM从入门到精通1:MVVM模式简介WPFMVVM从入门到精通2:实现一个登录窗口WPFMVVM从入门到精通3:数据绑定WPFMVVM从入门到精通4:命令和事件WPFMVVM从入门到精通5:PasswordBox的绑... 查看详情

wpfmvvm从入门到精通7:关闭窗口和打开新窗口

原文:WPFMVVM从入门到精通7:关闭窗口和打开新窗口 WPFMVVM从入门到精通1:MVVM模式简介WPFMVVM从入门到精通2:实现一个登录窗口WPFMVVM从入门到精通3:数据绑定WPFMVVM从入门到精通4:命令和事件WPFMVVM从入门到精通5:... 查看详情

anacondaconda常用命令:从入门到精通(代码片段)

目录1.前言2.管理conda自身2.1查看conda版本2.2 查看conda的环境配置2.4设置镜像2.5 更新conda2.6 更新Anaconda整体2.7 查询某个命令的帮助 3.管理环境3.1.创建虚拟环境3.2.创建虚拟环境的同时安装必要的包3.3查看有哪些虚拟环境3.4激活... 查看详情

vuejs从入门到精通(代码片段)

尚硅谷Vue2.0+Vue3.0全套教程,全网最新最强vuejs从入门到精通001课程简介002vue简介003Vue官网使用指南004搭建Vue开发环境005Hello小案例006分析Hello案例007模板语法008数据绑定009el与data的两种写法010理解MVVM011Object.define013Vue中的数... 查看详情

java从入门到精通oop(代码片段)

文章目录1面向对象11.1面向对象1.1.1概念1.1.2三大特征1.2类和对象1.2.1类1.2.2对象1.2.3类和对象的关系1.3类和对象的创建和使用1.3.1练习1:类的创建使用1.3.2对象在内存中的存储1.3.3单一对象内存图1.3.4练习2:创建多个类1.3.5... 查看详情

wpfmvvm从入门到精通2:实现一个登录窗口

我们究竟要做一个怎样的东西呢?直接上图:这看起来比较简单,但把这个登录窗口做完,MVVM的入门就基本完成了。(为什么登录界面要选择性别这么奇怪?无非是因为RadioButton的绑定也是一个课题)很多教程都是举一个小例子... 查看详情

wpfmvvm从入门到精通3:数据绑定

我们前面已经说过,现在后端和前端可以分头行事了。我们先来看看后端要做的事情。对应于用户名输入框,ViewModel里面应该有一个相应的对象。当这个对象状态发生改变时,需要向View发出一个通知。因为所有的属性都要做这... 查看详情

wpfmvvm从入门到精通1:mvvm模式简介

刚开始接触和使用MVVM模式的时候,就有一种感觉:哇,实现这么一丁点的功能,竟然要写这么多代码,太麻烦了吧!但是后来当我熟悉了这种模式之后,感觉就变成了:哇,还是这么麻烦。没错,使用MVVM模式的确要在项目中增... 查看详情

python从入门到精通—初识python(代码片段)

Python从入门到精通—初识PythonPython基础知识学习系列博客,持续更新Python从入门到精通—初识PythonPython从入门到精通—初识Python1、Python简介2、认识"Python"3、Python版本4、Python的功能5、Python语言优点6、Python语言缺点1、Py... 查看详情

python从入门到精通—初识python(代码片段)

Python从入门到精通—初识PythonPython基础知识学习系列博客,持续更新Python从入门到精通—初识PythonPython从入门到精通—初识Python1、Python简介2、认识"Python"3、Python版本4、Python的功能5、Python语言优点6、Python语言缺点1、Py... 查看详情

matlab从入门到精通:图像可视化基础操作(代码片段)

matlab图像可视化基本要求(1)掌握图形窗口的创建与控制,以及图形窗口的基本操作;(2)熟练掌握二维和三维绘图基本的命令、线型控制;(3)初步掌握用特殊的图形来表现特殊数据的性质,如面积图、直方图、饼图等。(... 查看详情

react从入门到精通总结(代码片段)

事件1.React事件处理采用的是小驼峰命名法,而不是小写2.React使用JSX语法时你需要传入一个函数作为事件处理函数//jsx<buttononClick=this.onFn>11111</button>js中的函数方法直接写一个字符串作为事件处理函数。//js<buttono... 查看详情

最全的monkeyrunner自动化测试从入门到精通

最基本脚本功能开始编写(1)Monkeyrunner和Monkey的区别1)Monkeyrunner工具在工作站上通过API定义的特定命令和事件控制设备或模拟器(可控)2)精确控制事件之间的事件3)可以进行:点触屏、拖拽、长按、键盘事件4)可以智能截... 查看详情

shell从入门到精通(14)read内置命令读取用户输入(代码片段)

ad命令的用法为:read[-options][variables]options表示选项,如下表所示;variables表示用来存储数据的变量,可以有一个,也可以有多个。options和variables都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量REPLY中。选... 查看详情

shell从入门到精通(10)信号捕获和处理(代码片段)

前言Linux利用信号与运行在系统中的进程进行通信。当你在终端中启动一个前台进程,按下(Ctrl+C),Linux内核会生成SIGINT信号中断该进程。而trap命令可以在信号出现时捕获,修改信号的默认处理动作。捕获信号trap命令允许你来指... 查看详情

axurerp从入门到精通(五十一)案例-超链接(代码片段)

超链接非常容易制作,随便拉个”链接按钮“即可,但是如何实现鼠标悬停时鼠标又原来的箭头变为小手呢?拖入一个链接按钮,并修改文本为忘记密码,为忘记密码添加单击事件,注意只添加事件不加任何动作;右键”单击时... 查看详情