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

转载:https://blog.csdn.net/lweiyue/article/details/88883780

这一部分,我们要做的事情,是把点击登录按钮的事情也在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)
					CommandMnaager.RequerySuggested+=value;
			}
			remove
			{
				if(_canExecute!=null)
					CommandManager.RequerySuggested-=value;
			}
		}
		
		public bool CanExecute(object parameter)
		{
			if(_canExecute==null)
				return ture;
			return _canExecute(paramter);
		}
		
		public void Execute(object paramter)
		{
			if(_execute!=null && parameter!=null)
			{
				_execute(parameter);
			}
		}
		
		private Func<object,bool> _canExecute;
		private Action<object> _execute;
	
		public BaseCommand(Action<object> execute,Func<object,bool> canExecute)
		{
			_execute = exute;
			_canExecute = canExecute;
		}
		
		public BaseCommand(Action<object> execute):
			this(execute,null)
		{
			
		}
	}
}

BaseCommand的功能很简单,就是执行命令前先判断一个命令能不能执行。
然后我们就可以绑定命令了,在后端这样写:

private BaseCommand clickLoginCommand;
public BaseComand ClickLoginCommand
{
	get
	{
		if(clickLoginCommand==null)
		{
			clickLoginCommand = new BaseCommand(new Action<object>(o=>{
				//执行登录逻辑
			}));
		}
		
		return clickLoginCommand;
	}
}

前端这样写:

<Button Content="登录" 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 (parameter != null)
            {
                parameter = CommandParameter;
            }
            if (Command != null)
            {
                Command.Execute(parameter);
            }
        }

        ///<summary>
        ///事件
        ///</summar>
        public ICommand Command
        {
            get
            {
                return (ICommand)GetValue(CommandProperty);
            }
            set
            {
                SetValue(CommandProperty, value);
            }
        }

        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(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(nameof(CommandParameter), typeof(object), typeof(EventCommand), new PropertyMetadata(null));
    }
}

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

private BaseCommand loginClick;

/// <summary>
/// 登录事件
/// </summary>
public BaseCommand LoginClick
{
	if(loginClick==null)
	{
		loginClick = new BaseCommand(new Action<object>(o)=>>{
			//执行登录逻辑
		});
	}
	return loginClick;
}

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

<Button Content="登录">
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="Click">
			<c:EventCommand Command="{Binding LoginClick}" />
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Button>

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值