MVVM WPF 开发必须掌握的框架
这里介绍的是使用 MVVMtoolkit 实现的方式;
安装插件:
1、解决方案 单击右键 选择nuget 管理
查找并安装下面的安装包
2、点击当前项目 点击右键 然后新键对应的 Models Views ViewModels 等文件夹
2、然后在Viewmodels 中新建立一个类,名字可以是 mainViewModel
在 mainViewModel 中的代码如下:
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Mvvmtoolkit.ViewModels
{
public class mainViewModel:ObservableObject
{
private int _value;
public int Value
{
get { return _value; }
set {
// 这种方式只要变更就会通知,不管数值是否有变化
//_value = value;
//this.OnPropertyChanged();
SetProperty<int>(ref _value, value);
// 数据有变化才会通知
}
}
public mainViewModel()
{
// 用于该模型的初始话
}
}
}
这个样的话就实现了一个,viewmodel 的搭建,该类主要的作用是 用来绑定UI界面的数据实现model和view之间的沟通;
UI如何绑定数据:
可以在UI xaml 中定义下面代码:
<StackPanel>
<TextBlock Text="{Binding Value}"/>
<TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
这里面的 {Binding Value } 就是将控件的Text和viewModel中的Value 绑定
但是需要在UI的逻辑代码中加入:
this.DataContext =new mainViewModel();
这样就实现了UI和view 之间的关联
实现效果:
在mainViewModel 中更改Value d的数值,前台的Text 会进行变更
更改前台TextBox 的数值,mainViewModel 中的value 数值,前台textBlock的数值也会改变。
但是不要忘记添加更新的触发器:UpdateSourceTrigger
command 的绑定
在MVVM 中按钮触发的命令一般也是通过绑定的方式实现的,下面介绍一种无传参的函数实现方式:
首先在前台需要增加一个 按钮然后绑定命令;
<Button Content="按钮" Command="{Binding Btncommand}"></Button>
这个代码的意思是 button 和Btncommand 绑定了,按下按钮后就会调用viewModel 中的Btncommand 函数;
然后在mainViewModel 中需要声明一个Btncommand()
public ICommand Btncommand { get; set; }
然后在 mainViewModel的初始话程序中需要实例化一个Btncommand
//初始话command
Btncommand = new RelayCommand(mycommand);
mycommand 是自行编写的回调函数,可以用来做button的触发动作
public void mycommand()
{
Task.Run(async () =>
{
while (true)
{
await Task.Delay(1000);
Value++;
}
});
}
command绑定如何传参数
command传参数的办法是使用 CommandParameter 可以传入字符串、可以传入绑定的属性
也可以传入对象,当然如果想要传入多个参数,可以将多个参数整合为一个对象然后传入;这个是目前最简单的办法;
// 传入字符串
<Button Content="按钮" Command="{Binding Btncommand}" CommandParameter="12" ></Button>
// 出入绑定的属性
<Button Content="按钮" Command="{Binding Btncommand}" CommandParameter="{Binding Value}"></Button>
//传入对象
<Button Content="按钮" Command="{Binding Btncommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}"></Button>
当然ViewModel中的代码也需要更改:
//初始话command
Btncommand = new RelayCommand<object>(mycommand);
public void mycommand(object obj)
{
Task.Run(async () =>
{
MessageBox.Show(obj.GetType().ToString());
while (true)
{
await Task.Delay(1000);
Value++;
}
});
}
AsyncRelayCommand()这个也是一种command的类型
编写方法同RelayCommand是一样的
1、也需要在button上面绑定一个命令 比如BtnAsynccommand
<Button Content="按钮" Command="{Binding BtnAsynccommand}" CommandParameter="{Binding Value}"></Button>
然后在viewModel中对其进行声明
public ICommand BtnAsynccommand { get; set; }
然后再对其进行初始话;
BtnAsynccommand=new AsyncRelayCommand<object> (myAsynccommand);
函数的书写方式参考:
public async Task myAsynccommand(object obj)
{
while (true)
{
await Task.Delay(1000);
Value++;
}
}
如何停止Task 然后继续开启一个新的Task
这个位置埋下一个伏笔,因为在实际使用中如果点击多次按钮就会出现数字一秒增加很多数值的情况;
多个界面之间如何传递数据
在写上位机中我们会经常出现一个疑问就是当存在多个界面的时候,如何在多个界面之间传递数据也是一个比较值得关注的问题;
下面介绍的是订阅和发布
这个如果不适用MVVMtoolkit 得话,需要使用Messenger
但是MVVMtoolkit 框架其实已经写好了,这里叫做WeakReferenceMessenger
同时需要ObserVableRecipient、Irecipient
下面实现一个多窗口之间传递数据的程序
首先建立一个新的窗口,然后为这个窗口创建一个ViewMoldel 可以命名为pageViewModel
该viewModel 的写法如下:
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Messaging;
using Mvvmtoolkit.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
namespace Mvvmtoolkit.ViewModels
{
class pageViewModel : ObservableRecipient, IRecipient<MessengerA>,IRecipient<MessengerB>
{
public pageViewModel()
{
this.IsActive = true;
}
public void Receive(MessengerA message)
{
MessageBox.Show("收到MessengerA");
}
public void Receive(MessengerB message)
{
MessageBox.Show("收到MessengerB");
}
}
}
其中IRecipient <>
<>中间用于放类型,可以是string,也可以是自己创建的类;
如:demo中的再models文件夹下面新键了两个类:
MessengerA MessengerB
这两个类可以用于不同界面向pageViewModel中写入数值
其实这里面只是一个对象,所以需要传递更多的数据可以写在对象中
类的编写代码:
using System;
using System.Collections.Generic;
using System.Text;
namespace Mvvmtoolkit.Models
{
public class MessengerA
{
}
}
mainViewModel中的代码如下:
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using Microsoft.Toolkit.Mvvm.Messaging;
using Mvvmtoolkit.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Mvvmtoolkit.ViewModels
{
//public class mainViewModel:ObservableObject
public class mainViewModel: ObservableRecipient,IRecipient<string>, IRecipient<MessengerA>
{
private int _value;
public int Value
{
get { return _value; }
set {
// 这种方式只要变更就会通知,不管数值是否有变化
//_value = value;
//this.OnPropertyChanged();
SetProperty<int>(ref _value, value);
// 数据有变化才会通知
}
}
public ValueModel ValueModel { get; set; }
public ICommand Btncommand { get; set; }
public ICommand BtnAsynccommand { get; set; }
public Task mytask { set; get; }
public mainViewModel()
{
// 用于该模型的初始话
this.IsActive = true;
//初始话command
Btncommand = new RelayCommand<object>(mycommand);
BtnAsynccommand=new AsyncRelayCommand<object> (myAsynccommand);
//订阅消息
//WeakReferenceMessenger.Default.Register<string>
// 发布消息
}
public async Task myAsynccommand(object obj)
{
//while (true)
//{
// await Task.Delay(1000);
// Value++;
//}
WeakReferenceMessenger.Default.Send<MessengerB>(new MessengerB());
}
public void mycommand(object obj)
{
WeakReferenceMessenger.Default.Send<MessengerA>(new MessengerA());
//WeakReferenceMessenger.Default.Send<string>("wwwwww");
//mytask = Task.Run(async () =>
//{
// MessageBox.Show(obj.GetType().ToString());
// while (true)
// {
// await Task.Delay(1000);
// Value++;
// }
//});
}
public void Receive(string message)
{
//throw new NotImplementedException();
}
public void Receive(MessengerA message)
{
//throw new NotImplementedException();
}
}
}
总结:
模块之间可以实现数据传递了,基本就可以做到很多事情了,剩下的就是按照需求来进行编写了。
多界面的切换方式可以参考上位机多窗口的编写方式_叮当说的博客-CSDN博客
本节的程序主要参考B站视频2021最新录制,WPF应用开发中的轻型级MVVM框架-MVVM Toolkit(WPF\C#\MVVM\框架)B0561_哔哩哔哩_bilibili