1)按钮和下面的文本框分别关联的对应的函数和一个属性;
2)关联对应的实例化的一个数据;
3)这个类中需要指定INotifyPropertyChanged接口,然后实现该接口对应的事件声明public event PropertyChangedEventHandler PropertyChanged;
4)Name参数,需要使用完全方式声明,在set中,增加对事件的调用,相当于,每次修改值的时候就出发事件,然后界面会收到该事件;发送事件中,一个参数中包括了事件的Name,形成对应;
5)界面收到后,会根据该参数进行更新。
<Button Name="bt1" Content="点击我" Command="{Binding myCommand}" Margin="5" Height="30"/>
<TextBox Name="tx1" Text="{Binding Name}" Margin="5" Height="30"/>
指定对应的数据源
this.bt1.DataContext = new MainViewModel();
this.tx1.DataContext = this.bt1.DataContext;
声明的类
public class MainViewModel:INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set {
name = value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Name"));
}
}
public ClassMyCommand myCommand { get; set; }
public MainViewModel() {
myCommand = new ClassMyCommand(Show);
Name = "first";
}
public event PropertyChangedEventHandler PropertyChanged;
public void Show()
{
Name = "点击了我。";
MessageBox.Show(Name);
}
}
6)在上面基础上修改简化,
首先声明一个基类,依然使用原来的通知接口,里面实现一个方法,用于实现参数修改后,调用事件
public class NotifyPropertyChangedBaseClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propertyname = "")//通过该方法可以直接获取调用者的名称 前提是需要有默认参数
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
public class MainViewModel: NotifyPropertyChangedBaseClass //INotifyPropertyChanged 修改原来基于接口,现在基于基类
{
private string name;
public string Name
{
get { return name; }
set {
name = value;
//PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Name"));
//OnPropertyChanged("Name");//参数可以不写,
OnPropertyChanged();//参数可以不写,
}
}
public ClassMyCommand myCommand { get; set; }
public MainViewModel() {
myCommand = new ClassMyCommand(Show);
Name = "first";
}
//public event PropertyChangedEventHandler PropertyChanged;//删除掉这个
public void Show()
{
Name = "点击了我。";
MessageBox.Show(Name);
}
}
7)使用MVVMLight
通过NuGet安装该安装包后,上面自己写的命令绑定和通知都可以删除;直接使用社区包中已经封装好的函数
public class MainViewModel: ViewModelBase //现在基于基类
{
private string name;
public string Name
{
get { return name; }
set {
name = value;
RaisePropertyChanged();//调用事件
}
}
public RelayCommand myCommand { get; set; }//定义命令
public MainViewModel() {
myCommand = new RelayCommand(Show);
Name = "first";
}
public void Show()
{
Name = "点击了我。";
MessageBox.Show(Name);
}
}
其中是三个点
基类——ViewModelBase //现在基于基类
事件调用——RaisePropertyChanged();//调用事件
命令定义——public RelayCommand myCommand { get; set; }//定义命令
命令赋值——myCommand = new RelayCommand(Show);
其中命令 有两个重载,一个带参数,一个努努带参数,带参数的调用函数的时候需要传递带参数的函数。根据需要调用。
GalaSoft.MvvmLight.CommandWpf.RelayCommand
GalaSoft.MvvmLight.CommandWpf.RelayCommand<T>
如果是传递参数
public RelayCommand<string> myCommand{ get; set; }//定义命令
public MainViewModel() {
myCommand = new RelayCommand<string> (Show);
Name = "first";
}
public void Show(string txt )
{
Name = "点击了我。";
MessageBox.Show(txt);
}
XAML中需要将参数传递进来
Command="{Binding myCommand}"
CommandParameter="{Binding ElementName=tx2, Path=Text}"
8)MVVMLight中的 消息注册和发送
//启动的时候定义一个消息接收器,当接收到消息,且关键字是 myToken1,这可以自定义,后就会自己执行委托 Show
Messenger.Default.Register<string>(this,"myToken1",Show);
Messenger.Default.Send( txt, "myToken1");//传递需要参数和 标识,用于和注册的匹配
9)使用Microsoft.Toolkit.Mvvm 包或者CommunityToolkit.Mvvm 两个是一样使用的,建议使用后面的。
消息注册换了一个名字
//启动的时候定义一个消息接收器,当接收到消息,且关键字是 myToken1,这可以自定义,后就会自己执行委托 Show
//Messenger.Default.Register<string>(this, "myToken1", Show);
WeakReferenceMessenger.Default.Register<string, string>(this, "myToken1", (o, e) => {
Show(e);
});
public class MainViewModel: ObservableObject //ViewModelBase MVVMLight //现在基于基类Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObject
{
private string name;
public string Name
{
get { return name; }
set {
name = value;
//RaisePropertyChanged();//调用事件
OnPropertyChanged();//调用事件
}
}
public RelayCommand<string> myCommand{ get; set; }//定义命令
public MainViewModel() {
myCommand = new RelayCommand<string> (Show);
Name = "first";
}
public void Show(string txt )
{
Name = "点击了我。";
//MessageBox.Show(txt);
WeakReferenceMessenger.Default.Send( txt, "myToken1");//传递需要参数和 标识,用于和注册的匹配
}
}
其他都没有变。
基类——ObservableObject//现在基于基类
事件调用——OnPropertyChanged();//调用事件
命令定义——public RelayCommand myCommand { get; set; }//定义命令
命令定义——public RelayCommand<string> myCommand{ get; set; }//定义命令 带参数的
命令赋值——myCommand = new RelayCommand<string> (Show);
通过命令牌发送消息 触发事件——
//Messenger.Default.Send( txt, "myToken1");//传递需要参数和 标识,用于和注册的匹配 MVVMLight
WeakReferenceMessenger.Default.Send( txt, "myToken1");//传递需要参数和 标识,用于和注册的匹配
注册事件——
//启动的时候定义一个消息接收器,当接收到消息,且关键字是 myToken1,这可以自定义,后就会自己执行委托 Show
//Messenger.Default.Register<string>(this, "myToken1", Show);
WeakReferenceMessenger.Default.Register<string, string>(this, "myToken1", (o, e) => {
Show(e);})
说明 o 的类型是 this <string, string> 第一个string 对应的是e,第二个对应的是 "myToken1" 如果传递的不是string就要在注册的时候也修改
对于有些public RelayCommand myCommand 执行过程中这个命令不想被再次执行,例如执行程序时会比较长时间,或者开启了子进程之类的,这时不想该命令再次执行时,可以通过下面的方式处理:
1)首先命令初始化的时候,之前一直使用传递一个参数,还有一个可以传递两个参数的,就是可以传递一个返回bool的函数;
RelayCommand = new RelayCommand(() => { }, () => { return true; });
具体两个函数可以自己添加逻辑,如果返回的是false就不能再执行,如果要想动态改变,则可以提前定义个属性(带通知的),然后返回这个值;通过再任意位置修改这个值,就可以修改他的可执行属性。
//
private bool _isCanexecute = true;
public bool IsCanExecute { get { return _isCanexecute; } set { _isCanexecute = value; OnPropertyChanged(); } }
public RelayCommand RelayCommand { get; set; }
RelayCommand = new RelayCommand(() => {
Task.Run(() => {
IsCanExecute = false;
for (int i = 0; i < 1000; )
{
#自己的逻辑
}
IsCanExecute = true;
});
}, () => { return IsCanExecute; });