WPF/MVVM 快速入门教程(2)

对于不太了解MVVM模式的读者在读这篇文章之前,应当先看看我之前的一片文章。

http://www.cnblogs.com/zhangzhi19861216/archive/2013/03/19/WPF-MVM.html

例3:命令

绑定到GUI事件是有问题的, WPF为我们提供了一个更好的方式,这就是ICommand。大多控件都有一个命令特性。对于简单示例,我们在这里只实现一个简单的类RelayCommand,它继承ICommand。

ICommand接口要求用户定义两个方法:bool CanExecute(object parameter)和void Execute(object parameter)。 CanExecute方法,定义用于确定此命令是否可以在其当前状态下执行的方法。在我们的例子中,我们不关心它,所以我们返回true,这意味着,我们一直可以执行命令。

因为我们想重用ICommand的代码,所以我们使用继承Icommand接口的类RelayCommand,它包含所有我们不想多写的复用代码。

为了表明ICommand是多么容易复用,我们绑定更新艺术家命令到一个按钮和一个菜单项。注意,我们不再绑定到特定按钮的Click事件,或菜单的Click事件。

让我们来看看代码:

在例3中我们添加了一个RelayCommand.cs文件,代码如下:

public class RelayCommand : ICommand

     {

           #region Members

           readonly Func<Boolean> _canExecute;

           readonly Action _execute;

           #endregion

 

           #region Constructors

           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 Members

           public event EventHandler CanExecuteChanged

           {

                add

                {

 

                     if (_canExecute != null)

                           CommandManager.RequerySuggested += value;

                }

                remove

                {

 

                     if (_canExecute != null)

                           CommandManager.RequerySuggested -= value;

                }

           }

 

           [DebuggerStepThrough]

           public Boolean CanExecute(Object parameter)

           {

                return _canExecute == null ? true : _canExecute();

           }

 

           public void Execute(Object parameter)

           {

                _execute();

           }

           #endregion

 

 

 

译者附加:

WPF的命令是实现了ICommand接口的类,ICommand接口非常简单,包含两个方法和一个事件。

如上代码,RelayCommand类继承了ICommand接口,因此实现了ICommand接口的两个方法和一个事件。

在RelayCommand类中我们定义了两个委托

readonly Func<Boolean> _canExecute;

readonly Action _execute;

_canExecute封装一个没有参数的方法,此方法有一个返回值,用在Boolean CanExecute(Object parameter)当中判断这个命令是否可以执行。

_execute封装一个既没有参数也没有返回值的方法,用在Execute(Object parameter)方法当中定义调用此命令时调用的方法。

CanExecuteChanged:当出现影响是否应执行该命令的更改时发生。通常,当发生该事件时,命令源对该命令调用 CanExecut,如果该命令无法执行,则命令源禁用其自身。

 

再来看看例3中SongViewModel类的代码,在例2的代码基础上,多了如下代码:

          int _count = 0;

           void UpdateArtistNameExecute()

           {

                ++_count;

                ArtistName = string.Format("Elvis ({0})", _count);

           }

           bool CanUpdateArtistNameExecute()

           {

                return true;

           }

 public ICommand UpdateArtistName { get { return new RelayCommand(UpdateArtistNameExecute, CanUpdateArtistNameExecute); } }

    

在SongViewModel类中定义了一个ICommand接口类型的属性UpdateArtistName,get返回的是RelayCommand类型的一个实例,其中new RelayCommand实例时构造函数传进了两个方法。让我们转到定义看一下。

又回到RelayCommand类中,看到如下代码:

public RelayCommand(Action execute, Func<Boolean> canExecute)

           {

                if (execute == null)

                     throw new ArgumentNullException("execute");

                _execute = execute;

                _canExecute = canExecute;

           }

在这里我们看到exeute指向传进来的UpdateArtistNameExecute方法,_canExecute指向CanUpdateArtistNameExecute方法。

再来看看view及MainWindow.xaml,

  <Window.DataContext>

        <local:SongViewModel />

    </Window.DataContext>

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto" />

            <ColumnDefinition Width="Auto" />

        </Grid.ColumnDefinitions>

        <Menu Grid.Row="0" Grid.ColumnSpan="3">

            <MenuItem Header="Test">

                <MenuItem Header="Update Artist" Command="{Binding UpdateArtistName}" />

            </MenuItem>

        </Menu>

        <Label Grid.Column="0" Grid.Row="1" Content="Example 3 - using ICommand!" />

        <Label Grid.Column="0" Grid.Row="2" Content="Artist:  " />

        <Label Grid.Column="1" Grid.Row="2" Content="{Binding ArtistName}" />

        <Button Grid.Column="1" Grid.Row="3" Name="ButtonUpdateArtist" Content="Update Artist Name" Command="{Binding UpdateArtistName}" />

    </Grid>

 

我们看到按钮和菜单项的命令都绑定到SongViewModel类实例的UpdateArtistName命令属性上。源代码清晰了,我们接下来看看WPF 的命令系统(引用《深入浅出WPF》):

命令系统构成要素

命令Command

命令源Command Source

命令目标Command Target

命令关联 CommandBinding

基本元素之间的关系

创建命令类:即获得一个实现ICommand接口的类。

声明命令实例:使用命令时需要创建命令类的实例。

指定命令源:由谁来发送这个命令。

指定命令目标:命令目标不是命令的属性而是命令源的属性(疑问)。

设置命令关联。

 

好了,现在我们又来分析我们的源代码。

1、 创建命令类,我们的RelayCommand类。

2、 声明命令实例,SongViewModel类中声明了一个命令属性UpdateArtistName.

3、 指定命令源:按钮和菜单项

4、 指定命令目标,绑定到ArtistName属性的Lable控件。

5、 命令关联,RelayCommand中CanExecute和Execute执行的方法。

运行程序,点击按钮,激发UpdateArtistName命令,如果CanExecute方法返回true(我们这里一直返回true),则执行Execute方法。即调用UpdateArtistNameExecute()方法更新ArtistName属性,因为ArtistName属性实现了INotifyPropertyChanged

接口的PropertyChangedEventHandler事件,所以Lable的内容跟着改变。

 代码地址:files.cnblogs.com/zhangzhi19861216/MVVMQuickStartTutorial.rar

你可能感兴趣的:(快速入门)