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提取出来作为一个框架,去更好地解决问题。