MVVM的目的是为了最大限度地降低了XAML文件和CS文件的耦合度,分离界面和业务逻辑,所以我们要尽可能的在View后台不写代码。但是这个例子中,我们将更新ViewModel的代码写在了View里,下一个例子中,我们要通过命令(<font style="color:rgb(51, 51, 51);">Command</font>
)的来将Button的事件分离出来。
Command
因为本文中需要使用<font style="color:rgb(51, 51, 51);">Command</font>
命令,我们先来简单了解<font style="color:rgb(51, 51, 51);">Command</font>
命令。在WPF中使用命令的步骤很简单:
1. <font style="color:rgb(51, 51, 51);">创建命令</font>
2. <font style="color:rgb(51, 51, 51);">绑定命令</font>
3. <font style="color:rgb(51, 51, 51);">设置命令源</font>
4. <font style="color:rgb(51, 51, 51);">设置命令目标</font>
WPF中命令的核心是**<font style="color:#E8323C;">System.Windows.Input.ICommand</font>**
接口,所有命令对象都实现了此接口。当创建自己的命令时,不能直接实现**<font style="color:#E8323C;">ICommand</font>**
接口,而是要使用<font style="color:rgb(51, 51, 51);">System.Windows.Input.RouteCommand</font>
类,该类已经实现了<font style="color:rgb(51, 51, 51);">ICommand</font>
接口,所有WPF命令都是**<font style="color:rgb(51, 51, 51);">RoutedCommand</font>**
类的实例。在程序中处理的大部分命令不是<font style="color:rgb(51, 51, 51);">RoutedCommand</font>
对象,而是<font style="color:rgb(51, 51, 51);">RoutedUICommand</font>
类的实例,它继承自<font style="color:rgb(51, 51, 51);">RoutedCommand</font>
类。
WPF提供了一个很好的方式来解决事件绑定的问题—<font style="color:rgb(51, 51, 51);">ICommand</font>
。很多控件都有**<font style="color:rgb(51, 51, 51);">Command</font>**
属性,**如果没有,我们可以将命令绑定到触发器上**。接下来我们来先实现一个ICommand接口。<font style="color:rgb(51, 51, 51);">ICommand</font>
需要用户定义两个方法<font style="color:rgb(51, 51, 51);">bool CanExecute</font>
和<font style="color:rgb(51, 51, 51);">void Execute</font>
。第一个方法可以让我们来判断是否可以执行这个命令,第二个方法就是我们具体的命令。
Name.cs代码沿用上一篇中的代码,不作修改,相应的名称空间换成Command即可。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Command
{
public class RelayCommand : ICommand
{
#region 字段
readonly Func<Boolean> _canExecute;
readonly Action _execute;
#endregion
#region 构造函数
public RelayCommand(Action execute):this(execute,null)
{
}
public RelayCommand(Action execute,Func<Boolean> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand 成员
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public void Execute(object parameter)
{
_execute();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Command
{
public class NameViewModel : INotifyPropertyChanged
{
public NameViewModel()
{
_userName = new Name() { UserName = "张三", CompanyName = "AAAAA" };
}
#region Fields
Name _userName;
#endregion
#region Property
public string UserName
{
get { return _userName.UserName; }
set { _userName.UserName = value; RaisePropertyChanged("UserName"); }
}
public string CompanyName
{
get { return _userName.CompanyName; }
set { _userName.CompanyName = value; RaisePropertyChanged("CompanyName"); }
}
#endregion
#region INotifyPropertyChanged属性
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region 属性更改方法
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region 命令
void UpdateNameExecute()
{
this.UserName = "李四";
this.CompanyName = "BBBBB";
}
bool CanUpdateNameExecute()
{
return true;
}
public ICommand UpdateName
{
get { return new RelayCommand(UpdateNameExecute, CanUpdateNameExecute); }
}
#endregion
}
}
<Window x:Class="Command.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Command"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="400">
<Window.DataContext>
<!--声明并创建一个NameViewModel的实例-->
<local:NameViewModel/>
</Window.DataContext>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<TextBlock Text="用户名:" Margin="20"/>
<TextBlock Text="{Binding UserName}" Margin="0,20"/>
<TextBlock Text="公司名称:" Margin="20"/>
<TextBlock Text="{Binding CompanyName}" Margin="0,20"/>
<Button Content="更新" Command="{Binding UpdateName}" Margin="20"/>
</StackPanel>
</Window>
下篇文章将把MVVM提取出来作为一个框架,去更好地解决问题。