引言

在本贴中,我们将学习WPF Commands。 Commands 可以很好地与 MVVM 模式 (Model- View-ViewModel)结合在一起。我们也将看到,视图(view)实际上是怎样知道和怎样调用它的使用WPF 命令( Commands )的视图模型(ViewModel)。

背景

下面我们一步一步讨论而不是立即查看完整的代码,这也可以较好地帮助我们理解代码的每一部分。

让我们看一下MVVM的体系结构。

我们约定使用下列标准术语:

  • Views 表示后缀为view的文件名 。(例如: StudentListView)
  • ViewModels 表示后缀为ViewModel的文件。(例如:StudentListViewModel)
  • Models 表示后缀为Model的文件。 (例如: StudentModel).

使用代码

原理介绍已经足够了。下面深入代码了解一个可以工作的MVVM例子,了解怎样在MVVM使用命令。

使用 Visual Studio 建立一个新WPF项目。按照上面的约定,把文件名MainWindow更改为 MainWindowView。

接着,我们需要建立一个新的类,名字为 MainWindowViewModel ,它将担当视图MainWindowView的视图模型ViewModel)。

我们在这里所做的是,在MVVM内,我们告诉视图,它的视图模型是什么。这可以通过为视图设置 Data Context来完成。在视图模型文件里有ViewModel,然而他们现在还不具有某些特定的视图之间的任何连接。

设置Datacontext的代码看起来是下面的样子。

打开 MainWindowView.xaml.cs并设置 data context 如下。

MainWindowView.xaml.cs

 
<Window x:Class="WpfExample.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfExample"> <Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext> <Grid>
</Grid>
</Window>

这里的本地命名空间别名为WpfExample。这是必要的,这样 framework知道MainWindowViewModel在哪里可以找到。

我们通过一个简单的绑定来验证这个。

让我们添加一个button查看,使用视图模型的一个实例设置button的content 。

视图

添加一个查看按钮并设置它的绑定内容如下。

MainWindowView.xaml.cs

<Window x:Class=" WpfMvvmExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfMvvmExample"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"> <Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext> <Grid>
<Button Width="100"
Height="100" Content="{Binding ButtonContent}"/>
</Grid>
</Window>

视图模型

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace WpfExample
{
    class MainWindowViewModel
    {
        public string ButtonContent
        {
            get
            {
                return "Click Me";
            }
        }
    }
}

在上面代码中,我们告诉视图,从视图模型所呈现的ButtonContent属性获取按钮的内容。

<Button Width="100" Height="100" Content="{Binding ButtonContent}"/>

现在如果运行应用,我们可以看到按钮的内容为 字符串(string) Click Me”.

这表明我们的MVVM可以正常工作。

现在我们转移到ICommand 接口(ICommand Interface)

现在,我们使用WPF命令为按钮添加一个点击功能。

在MVVM中,命令为通过视图更新模型提供了一种机制。

首先,我们看一下ICommand接口。

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

我们建立一个应用样板。当点击按钮时显示一个“HI"消息框,我们添加另一个按钮,切换hi按钮是否可以点击。

我们建立一个RelayCommand类,实现ICommand接口。这个类增强ICommand并分离代码作为一个独立的类。

This class acts as Enhancement for the ICommand and extracts the boiler plate code to a separate class.

public class RelayCommand : ICommand
{
private Action<object> execute; //定义成员 private Predicate<object> canExecute;//Predicate:述语//定义成员 private event EventHandler CanExecuteChangedInternal;//事件 public RelayCommand(Action<object> execute) //定义Action,CanExecute
: this(execute, DefaultCanExecute)
{
} public RelayCommand(Action<object> execute, Predicate<object> canExecute)//定义
{
if (execute == null)
{
throw new ArgumentNullException("execute");
} if (canExecute == null)
{
throw new ArgumentNullException("canExecute");
} this.execute = execute;
this.canExecute = canExecute;
} public event EventHandler CanExecuteChanged //CanExecuteChanged事件处理方法
{
add
{
CommandManager.RequerySuggested += value;
this.CanExecuteChangedInternal += value;
} remove
{
CommandManager.RequerySuggested -= value;
this.CanExecuteChangedInternal -= value;
}
} public bool CanExecute(object parameter) //CanExecute方法
{
return this.canExecute != null && this.canExecute(parameter);
} public void Execute(object parameter) //Execute方法
{
this.execute(parameter);
} public void OnCanExecuteChanged() //OnCanExecute方法
{
EventHandler handler = this.CanExecuteChangedInternal;
if (handler != null)
{
//DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
handler.Invoke(this, EventArgs.Empty);
}
} public void Destroy() //销毁方法
{
this.canExecute = _ => false;
this.execute = _ => { return; };
} private static bool DefaultCanExecute(object parameter) //DefaultCanExecute方法
{
return true;
}
}

CommandManager.RequerySuggested 负责使能和禁用 "Click to Hii" 按钮.

视图

<Window x:Class="WpfExample.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfExample"> <Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext> <Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition/>
</Grid.RowDefinitions> <Button Grid.Row="0" Command="{Binding HiButtonCommand}"
CommandParameter="Hai" Content="{Binding HiButtonContent}"
Width="100"
Height="100" /> <Button Grid.Row="1" Content="Toggle Can Click"
Command="{Binding ToggleExecuteCommand}" Width="100" Height="100"/>
</Grid> </Window>

视图模型

class MainWindowViewModel
{
private ICommand hiButtonCommand; private ICommand toggleExecuteCommand { get; set; } private bool canExecute = true;    //初始化为true public string HiButtonContent     //定义公开属性
{
get
{
return "click to hi";
}
} public bool CanExecute //定义公开属性
{
get
{
return this.canExecute;
} set
{
if (this.canExecute == value)
{
return;
} this.canExecute = value;
}
} public ICommand ToggleExecuteCommand //定义接口
{
get
{
return toggleExecuteCommand;
}
set
{
toggleExecuteCommand = value;
}
} public ICommand HiButtonCommand //定义接口
{
get
{
return hiButtonCommand;
}
set
{
hiButtonCommand = value;
}
} public MainWindowViewModel() //构造函数
{
HiButtonCommand = new RelayCommand(ShowMessage, param => this.canExecute);
toggleExecuteCommand = new RelayCommand(ChangeCanExecute);
} public void ShowMessage(object obj) //消息 方法
{
MessageBox.Show(obj.ToString());
} public void ChangeCanExecute(object obj) //方法
{
canExecute = !canExecute;
}
}

最后的运行结果好像是这样:

基本MVVM 和 ICommand用法举例(转)的更多相关文章

  1. c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例

    c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...

  2. 【转】awk 里的substr函数用法举例

    awk 里的substr函数用法举例: 要截取的内容:2007-08-04 04:45:03.084 - SuccessfulTradeResult(status: 1, currencyPair: ...

  3. 12. nc/netcat 用法举例

    nc命令用法举例 什么是nc nc是netcat的简写,有着网络界的瑞士军刀美誉.因为它短小精悍.功能实用,被设计为一个简单.可靠的网络工具 nc的作用 (1)实现任意TCP/UDP端口的侦听,nc可 ...

  4. 线程框架Executor的用法举例

    java5线程框架Executor的用法举例 Executor 是 java5 下的一个多任务并发执行框架(Doug Lea),可以建立一个类似数据库连接池的线程池来执行任务.这个框架主要由三个接口和 ...

  5. java8中的localdate和localtime用法举例

    java8中的localdate和localtime用法举例如下:这两个方法使我们可以方便的实现将旧的日期类转换为新的日期类,具体思路都是通过Instant当中介,然后通过Instant来创建Loca ...

  6. sql的游标用法举例(Cursor)

    sql的游标用法举例 ), ) Declare authors_cursor Cursor For Select Name,TrueName From Account Open authors_cur ...

  7. mysql操作查询结果case when then else end用法举例

    Case具有两种格式.简单Case函数和Case搜索函数. --简单Case函数 CASE sex          WHEN '1' THEN '男'          WHEN '2' THEN ...

  8. python yield用法举例说明

    1  yield基本用法 典型的例子: 斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到.1 2 3 5 8…… def fab(ma ...

  9. django models 中choices之用法举例

    CHOICES常用做单选属性,下面举例在django models中人物性别的用法: 我们先定义一个模型,名字为Students ,这个Students 包含了名字和性别两个字段,代码如下: from ...

随机推荐

  1. Linux stat函数和stat命令

    stat函数和stat命令 linux文件里的[inode = index node]解释:要理解inode必须了解磁盘和[目录项],inode实际是连接[目录项]和磁盘的中间物质. 图里的大圈代表硬 ...

  2. pytest框架之命令行参数1

    前言 pytest是一款强大的python自动化测试工具,可以胜任各种类型或者级别的软件测试工作.pytest提供了丰富的功能,包括assert重写,第三方插件,以及其他测试工具无法比拟的fixtur ...

  3. docker 发布到私有docker registry

    1.使用vs发布项目到文件夹: 2.在文件夹中新建dockerfile文件, 内容: FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-sli ...

  4. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  5. Linux vi/vim编辑器常用命令与用法总结

    (一)vi/vim是什么?Linux世界几乎所有的配置文件都是以纯文本形式存在的,而在所有的Linux发行版系统上都有vi编辑器,因此利用简单的文字编辑软件就能够轻松地修改系统的各种配置了,非常方便. ...

  6. Javascript高级编程学习笔记(99)—— WebGL(5) 绘图

    绘图 WebGL只能绘制三种形状: 点 线 三角 其它的形状都是由上面的三种形状合成之后绘制到三维空间中的 执行绘图操作 WebGL 提供了两种方法: gl.drawElements() gl.dra ...

  7. #Java学习之路——基础阶段二(第二篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  8. 解决MUI阻止a标签默认跳转事件—方法总结

    用过mui的小伙伴们一定不会陌生,有时候真的很烦mui本身会阻止a标签默认跳转.一般只要用了mui的ui组件,比如头部,底部或者弹框,你就不能在用a标签进行跳转了. 注:项目中引用了mui后,可能也会 ...

  9. java SE Development kit 8 Update 201 (64-bit) 的安装相关

    登录http://www.oracle.com,下载JDK(J2SE) JDK 1.0,1.1,1.2,1.3,1.4 1.5 (JDK5.0) à支持注解.支持泛型   1.6(JDK6.0) à ...

  10. 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(下)

    上一篇文章:https://www.cnblogs.com/cgzl/p/9734083.html 处理数据 嵌套字段 看例子: 我想查看viewer下的repositories.注意里面的edges ...