WPF MVVM from entry to the master 4: Command and events

In this section we going to do, is to click the login button events are realized in ViewModel. If not using the MVVM pattern, XAML file might look like this:
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Width="200" Height="30" Click="Button_Click"/>

The CS files with XAML files related to where it is this:

private void Button_Click(object sender, RoutedEventArgs e) { //业务处理逻辑代码 }

Thus, front and rear ends are coupled together and the code. In fact, commands and events are bound to be, just like data.

Let's take a look at command. ICommand is the interface to all commands, it is mainly do two things, this command can be executed, and execute the command.

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

For example, when a user name is empty, we may disable button. When the login button with a command to bind together, CanExecute will continue to be implemented, if it returns false, IsEnabled property of the button will be set to false.

Under normal circumstances, we need to extend the ICommand interface for development.

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 function is very simple, that is, before executing the command to determine what commands can not be executed.

Then we can bind command, so write in the backend:

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

Front-end write:

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

Click the button to perform the login logic code so complete. But do not rush to copy the code, because we do not intend to use the command.

We know, for operation buttons, it is not necessarily a click, possibly mouse across, probably right click. What is it that triggers Command? It is to click, not the other. For other controls, such as input box, what Command and on behalf of it? Command text change event can do? These problems make us feel confused, it is generally in the project, I will only use the event, instead of using the command (even click event).

This class can also keep BaseCommand, we also need to use the back. Before the introduction of the event, we want to reference a dll: System.Windows.Interactivity.dll. This dll is not the standard .NET Framework, it is a library of Blend. Can be found in the extended episode of the program:

If you do not find (after I installed VS2017 not found), only need to install the following libraries:

Well, cited System.Windows.Interactivity.dll, we can begin to talk about the event.

Some events are parameters, such as a mouse to move the event, will take the position of the mouse. But the command we used before, the default argument passed is null. In order to be able to pass parameters, we need to define a base class event:

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)); } } 

Now, we can add the following code in the ViewModel:

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

And then in the XAML file, to join i This namespace: xmlns: i = "http://schemas.microsoft.com/expression/2010/interactivity", and then modify the code button:

<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>

The code above noted, Click this event, bound to LoginClick this property. When we click on the button when, LoginClick inside of Action will be executed.

In this section we going to do, is to click the login button events are realized in ViewModel. If not using the MVVM pattern, XAML file might look like this:
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Width="200" Height="30" Click="Button_Click"/>

The CS files with XAML files related to where it is this:

private void Button_Click(object sender, RoutedEventArgs e) { //业务处理逻辑代码 }

Thus, front and rear ends are coupled together and the code. In fact, commands and events are bound to be, just like data.

Let's take a look at command. ICommand is the interface to all commands, it is mainly do two things, this command can be executed, and execute the command.

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

For example, when a user name is empty, we may disable button. When the login button with a command to bind together, CanExecute will continue to be implemented, if it returns false, IsEnabled property of the button will be set to false.

Under normal circumstances, we need to extend the ICommand interface for development.

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 function is very simple, that is, before executing the command to determine what commands can not be executed.

Then we can bind command, so write in the backend:

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

Front-end write:

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

Click the button to perform the login logic code so complete. But do not rush to copy the code, because we do not intend to use the command.

We know, for operation buttons, it is not necessarily a click, possibly mouse across, probably right click. What is it that triggers Command? It is to click, not the other. For other controls, such as input box, what Command and on behalf of it? Command text change event can do? These problems make us feel confused, it is generally in the project, I will only use the event, instead of using the command (even click event).

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就会被执行。

Guess you like

Origin www.cnblogs.com/ljdong7/p/12040172.html