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. 1. <font style="color:rgb(51, 51, 51);">创建命令</font>
  2. 2. <font style="color:rgb(51, 51, 51);">绑定命令</font>
  3. 3. <font style="color:rgb(51, 51, 51);">设置命令源</font>
  4. 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即可。
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows.Input;
  8. namespace Command
  9. {
  10. public class RelayCommand : ICommand
  11. {
  12. #region 字段
  13. readonly Func<Boolean> _canExecute;
  14. readonly Action _execute;
  15. #endregion
  16. #region 构造函数
  17. public RelayCommand(Action execute):this(execute,null)
  18. {
  19. }
  20. public RelayCommand(Action execute,Func<Boolean> canExecute)
  21. {
  22. if (execute == null)
  23. {
  24. throw new ArgumentNullException("execute");
  25. }
  26. _execute = execute;
  27. _canExecute = canExecute;
  28. }
  29. #endregion
  30. #region ICommand 成员
  31. public event EventHandler CanExecuteChanged
  32. {
  33. add
  34. {
  35. if (_canExecute != null)
  36. CommandManager.RequerySuggested += value;
  37. }
  38. remove
  39. {
  40. if (_canExecute != null)
  41. CommandManager.RequerySuggested -= value;
  42. }
  43. }
  44. [DebuggerStepThrough]
  45. public bool CanExecute(object parameter)
  46. {
  47. return _canExecute == null ? true : _canExecute();
  48. }
  49. public void Execute(object parameter)
  50. {
  51. _execute();
  52. }
  53. #endregion
  54. }
  55. }
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows.Input;
  8. namespace Command
  9. {
  10. public class NameViewModel : INotifyPropertyChanged
  11. {
  12. public NameViewModel()
  13. {
  14. _userName = new Name() { UserName = "张三", CompanyName = "AAAAA" };
  15. }
  16. #region Fields
  17. Name _userName;
  18. #endregion
  19. #region Property
  20. public string UserName
  21. {
  22. get { return _userName.UserName; }
  23. set { _userName.UserName = value; RaisePropertyChanged("UserName"); }
  24. }
  25. public string CompanyName
  26. {
  27. get { return _userName.CompanyName; }
  28. set { _userName.CompanyName = value; RaisePropertyChanged("CompanyName"); }
  29. }
  30. #endregion
  31. #region INotifyPropertyChanged属性
  32. public event PropertyChangedEventHandler PropertyChanged;
  33. #endregion
  34. #region 属性更改方法
  35. private void RaisePropertyChanged(string propertyName)
  36. {
  37. PropertyChangedEventHandler handler = PropertyChanged;
  38. if (handler != null)
  39. {
  40. handler(this, new PropertyChangedEventArgs(propertyName));
  41. }
  42. }
  43. #endregion
  44. #region 命令
  45. void UpdateNameExecute()
  46. {
  47. this.UserName = "李四";
  48. this.CompanyName = "BBBBB";
  49. }
  50. bool CanUpdateNameExecute()
  51. {
  52. return true;
  53. }
  54. public ICommand UpdateName
  55. {
  56. get { return new RelayCommand(UpdateNameExecute, CanUpdateNameExecute); }
  57. }
  58. #endregion
  59. }
  60. }
  1. <Window x:Class="Command.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:Command"
  7. mc:Ignorable="d"
  8. Title="MainWindow" Height="450" Width="400">
  9. <Window.DataContext>
  10. <!--声明并创建一个NameViewModel的实例-->
  11. <local:NameViewModel/>
  12. </Window.DataContext>
  13. <StackPanel VerticalAlignment="Center" Orientation="Horizontal">
  14. <TextBlock Text="用户名:" Margin="20"/>
  15. <TextBlock Text="{Binding UserName}" Margin="0,20"/>
  16. <TextBlock Text="公司名称:" Margin="20"/>
  17. <TextBlock Text="{Binding CompanyName}" Margin="0,20"/>
  18. <Button Content="更新" Command="{Binding UpdateName}" Margin="20"/>
  19. </StackPanel>
  20. </Window>
  1. 下篇文章将把MVVM提取出来作为一个框架,去更好地解决问题。