勇哥注:
此系列贴子服务于C# winform开发工程师,帮助他们快速了解wpf技术,节省大家的学习成本。
因此,这个系列不是讲给初学者听的。
我们知道winform是C#的标准ui框架,wpf则是另一种ui框架,随着.net Core的流行,它会是今后的主流选择,我们必须学习它。
系列贴子导航:
MVVM模式,它是三个词的缩写(Model, View, ViewModel),意义如下:
Model: 数据模型
它是把界面要显示的数据按面向对象方式进行表示出来,第2篇示例中的MainViewModel类定义的那些属性,就是数据模型做的事。
View: 界面
即xaml标签定义的界面。
ViewModel: 业务逻辑处理
如界面按钮这些控件的事件代码,就是业务逻辑处理的代码。
MVVM模式把桌面软件的开发分为上面说的三个层面(Model, View, ViewModel),
最主要的是把View和ViewModel进行解耦,以达到界面与业务逻辑的分离。
而Model和ViewModel是一个强关联的关系,这一点,通过本篇文章你就会看得到。
Model可以有许多个(因为复杂界面的数据更新是按功能进行分块的),这样ViewModel中可以有多个Model。
通过上篇贴子《wpf快速了解(2)事件驱动和数据驱动》完成了数据驱动的演示后,该代码离MVVM模式比较接近了。
本篇完成后,基本上就能看到MVVM模式的样子了。
勇哥说下本篇的新需求:
仍然实现上篇的功能,但是要求按钮事件里完全没有代码,即下面的代码都没有了。
private void ButRead_Click(object sender, RoutedEventArgs e) { model.Value = "100"; }
这样整个界面后台代码只存在一句 this.DataContext = model;
public MainWindow() { InitializeComponent(); this.DataContext = model; }
我们先在MainViewModel中添加一个属性。
private ICommand myCommandValue; public ICommand MyCommandValue { get { return myCommandValue; } set { myCommandValue = value; } }
把“读”按钮的Click删除掉,换成Command
这个Command实际还是Click事件,但是它可以绑定对象属性MyCommandValue,
点击按钮后会执行这个属性的代码。
下面的 {Binding MyCommandValue} 即是本文的主题“行为绑定”。
<Button Name="ButRead" Content="读" HorizontalAlignment="Left" Margin="22,173,0,0" VerticalAlignment="Top" Height="24" Width="78" Grid.Column="1" Command="{Binding MyCommandValue}" />
由于上面的属性MyCommandValue,它的类型是一个接口ICommand,所以我们得做一个实现类。
这个实现类的默认内容如下:
两个方法,一个事件,啥用处?继续看。。。
internal class CommandValue : ICommand { public event EventHandler? CanExecuteChanged; public bool CanExecute(object? parameter) { throw new NotImplementedException(); } public void Execute(object? parameter) { throw new NotImplementedException(); } }
回到MainViewModel的MyCommandValue属性定义。
这里我们new一个CommandValue做为myCommandValue的初始值。
private ICommand myCommandValue=new CommandValue(); public ICommand MyCommandValue { get { return myCommandValue; } set { myCommandValue = value; } }
好了,我们来研究第一个方法Execute,它是带参数的。
这个参数调用者可以不传,但是如果要专的话,要在xaml里面加标签。
public void Execute(object? parameter) { throw new NotImplementedException(); }
如下:
添加属性 CommandParameter传入参数。执行后字符串"hackpig"会传入函数Excute
<Button Name="ButRead" Content="读" HorizontalAlignment="Left" Margin="22,173,0,0" VerticalAlignment="Top" Height="24" Width="78" Grid.Column="1" Command="{Binding MyCommandValue}" CommandParameter="hackpig" />
我们来完成函数Excute的功能,但是出现下面注释的问题。
怎么办?
public void Execute(object? parameter) { //控制逻辑 //此处原意是想写 Value=100,但是此处访问不到Value }
这时候我们可以定义一个委托,然后在后面再让ICommand接口的 MyCommandValue属性去执行这个委托。
如下:
internal class CommandValue : ICommand { public event EventHandler? CanExecuteChanged; public bool CanExecute(object? parameter) { return true; } public void Execute(object? parameter) { //控制逻辑 //此处原意是想写 Value=100,但是此处访问不到Value OnAction?.Invoke(parameter); } public Action<object?> OnAction { get; set; } }
MyCommandValue属性这边我们这样写:
private ICommand myCommandValue; public ICommand MyCommandValue { get { if (myCommandValue == null) { myCommandValue = new CommandValue() { OnAction = new Action<object?>(Action1) }; } return myCommandValue; } set { myCommandValue= value; } } private void Action1(object? para) { Value= "100"; }
至此,勇哥已经完成了本例的要求,如下图所示:
我们在UI的后台代码中已经看到了跟业务逻辑有关的任何代码了。
就只剩下那一句“this.DataContext = model;”
至此,我们的MVVM模式已经基本成型了。
本文源码下载:
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

