CommunityToolkit.Mvvm详解
属性可视化
给一个属性添加ObservableProperty就可以可视化了
[ObservableProperty]
private string currentNameInfo;[ObservableProperty]
private string currentClassInfo;[ObservableProperty]
private string currentPhoneInfo;
xaml中只需要绑定大写的属性就可以了
<StackPanel Orientation="Horizontal"Grid.ColumnSpan="2"Grid.Row="1"><TextBlock Width="200"Height="40"FontSize="30"Text="{Binding CurrentNameInfo,TargetNullValue=null}"HorizontalAlignment="Center" /><TextBlock Width="200"Height="40"FontSize="30"Text="{Binding CurrentClassInfo,TargetNullValue=null}"HorizontalAlignment="Center" /><TextBlock Grid.Row="1"Width="200"Height="40"FontSize="30"Text="{Binding CurrentPhoneInfo,TargetNullValue=null}"HorizontalAlignment="Center" />
</StackPanel>
命令
可以用RelayCommand来简便的指定命令
[RelayCommand]
void AddButtonClick()
{Student student = new Student(NameProperty, ClassProperty, PhoneProperty);WeakReferenceMessenger.Default.Send(new ValueChangedMessage<Student>(student));
}
xaml中只需要绑定方法名加Command就可以了
<Button Grid.Row="3"Content="存入列表"Height="40"IsEnabled="{Binding CanAllow}"Command="{Binding AddButtonClickCommand}"Width="100" />
Message
传递自定义类
两个ViewModel之间传递自定义类
1.定义一个自定义的类
public record StringMessage(string message);
2.注册自定义类
通过WeakReferenceMessenger来注册StringMessage
public partial class ReciverUCViewModel:ObservableObject
{[ObservableProperty]private string? recivetxt;public ReciverUCViewModel(){WeakReferenceMessenger.Default.Register<StringMessage>(this, Receive);}private void Receive(object recipient, StringMessage message){Recivetxt = message.message;}
}
3.发送消息
public partial class SenderUCViewModel : ObservableObject
{//[ObservableProperty]//private string? sendertxt="null";private string? sendertxt;public string Sendertxt{get { return sendertxt; }set{if (SetProperty(ref sendertxt, value)){WeakReferenceMessenger.Default.Send(new StringMessage(value));}}}
}
传递PropertyChangedMessage
接收
public partial class ReciverUCViewModel:ObservableObject
{[ObservableProperty]private string? recivetxt;public ReciverUCViewModel(){WeakReferenceMessenger.Default.Register<PropertyChangedMessage<string>>(this,Receive);}private void Receive(object recipient, PropertyChangedMessage<string> message){Recivetxt = message.NewValue;}
}
可以用IRecipient来优化简便代码
public partial class ReciverUCViewModel : ObservableObject, IRecipient<PropertyChangedMessage<string>>
{[ObservableProperty]private string? recivetxt;public ReciverUCViewModel(){WeakReferenceMessenger.Default.Register(this);}public void Receive(PropertyChangedMessage<string> message){Recivetxt = message.NewValue;}
}
发送
public partial class SenderUCViewModel : ObservableObject
{//[ObservableProperty]//private string? sendertxt="null";private string? sendertxt;public string Sendertxt{get { return sendertxt; }set{if (SetProperty(ref sendertxt, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this,nameof(Sendertxt),default,value));}}}
}
传递RequestMessage
发送
public partial class SenderUCViewModel : ObservableObject
{//[ObservableProperty]//private string? sendertxt="null";private string? sendertxt;public string Sendertxt{get { return sendertxt; }set{if (SetProperty(ref sendertxt, value)){var res=WeakReferenceMessenger.Default.Send(new RequestMessage<string>());sendertxt = res.Response;}}}
}
接收
public partial class ReciverUCViewModel : ObservableObject,IRecipient<RequestMessage<string>>
{[ObservableProperty]private string? recivetxt;public ReciverUCViewModel(){WeakReferenceMessenger.Default.Register(this);}public void Receive(RequestMessage<string> message){recivetxt = message.ToString();message.Reply("hello");}}
简化
ObservableRecipient
可以替代ObservableObject,还能简化注册功能,设置属性IsActive=true就可以免注册
IRecipient
可以直接指明,要接收的类型
public partial class ReciverUCViewModel : ObservableRecipient,IRecipient<PropertyChangedMessage<string>>
{[ObservableProperty]private string? recivetxt;public ReciverUCViewModel(){//WeakReferenceMessenger.Default.Register(this);this.IsActive = true;}public void Receive(PropertyChangedMessage<string> message){Recivetxt = message.NewValue;}
}
心得
对于发送的相同类型的message,可以通过属性的名称来区分,分别处理
发送
public partial class FormUCViewModel:ObservableRecipient
{private string nameProperty;public string NameProperty{get { return nameProperty; }set {if (SetProperty(ref nameProperty, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(NameProperty), default, value));}}}private string classProperty;public string ClassProperty{get { return classProperty; }set {if (SetProperty(ref classProperty, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(ClassProperty), default, value));}}}private string phoneProperty;public string PhoneProperty{get { return phoneProperty; }set {if (SetProperty(ref phoneProperty, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(PhoneProperty), default, value));}}}}
接收
public partial class MainWindowViewModel:ObservableRecipient,IRecipient<PropertyChangedMessage<string>>
{[ObservableProperty]private string currentNameInfo;[ObservableProperty]private string currentClassInfo;[ObservableProperty]private string currentPhoneInfo;public MainWindowViewModel(){this.IsActive = true;}public void Receive(PropertyChangedMessage<string> message){// 根据消息的属性名称更新相应的属性switch (message.PropertyName){case nameof(FormUCViewModel.NameProperty):CurrentNameInfo = message.NewValue;break;case nameof(FormUCViewModel.ClassProperty):CurrentClassInfo = message.NewValue;break;case nameof(FormUCViewModel.PhoneProperty):CurrentPhoneInfo = message.NewValue;break;}}
}
功能展示
传递变化的属性
输入框代码
属性变化,底下的TextBlock也会跟着变化
ObservableProperty可以添加可视化属性,让前端绑定
NotifyPropertyChangedRecipients可以通知订阅了的类,属性变化
public partial class FormUCViewModel:ObservableRecipient
{//现代化写法[ObservableProperty][NotifyPropertyChangedRecipients]private string nameProperty;//现代化写法[ObservableProperty][NotifyPropertyChangedRecipients]private string classProperty;//老式写法private string phoneProperty;public string PhoneProperty{get { return phoneProperty; }set {if (SetProperty(ref phoneProperty, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(PhoneProperty), default, value));}}}}
显示的TextBlock代码
属性变化接收到不同的message,可以用message.PropertyName来区分接收的属性
public partial class MainWindowViewModel:ObservableRecipient,IRecipient<PropertyChangedMessage<string>>
{[ObservableProperty]private string currentNameInfo;[ObservableProperty]private string currentClassInfo;[ObservableProperty]private string currentPhoneInfo;public MainWindowViewModel(){this.IsActive = true;}public void Receive(PropertyChangedMessage<string> message){// 根据消息的属性名称更新相应的属性switch (message.PropertyName){case nameof(FormUCViewModel.NameProperty):CurrentNameInfo = message.NewValue;break;case nameof(FormUCViewModel.ClassProperty):CurrentClassInfo = message.NewValue;break;case nameof(FormUCViewModel.PhoneProperty):CurrentPhoneInfo = message.NewValue;break;}}
}
ToggleButton用NotifyPropertyChangedRecipients来通知订阅方属性变化了
[ObservableProperty]
[NotifyPropertyChangedRecipients]
private bool isAdd;
xaml
<ToggleButton IsChecked="{Binding IsAdd}"Grid.Row="1"Margin="5,8"HorizontalAlignment="Center"Style="{StaticResource ToggleButtonSwitch}"hc:VisualElement.HighlightBrush="{DynamicResource DangerBrush}" />
Receive接收到了数据要用(message.PropertyName来判断一下,以防接收到别的乱七八糟的数据(必须要弄,这个报错搞死我了)
public partial class FormUCViewModel:ObservableRecipient,IRecipient<PropertyChangedMessage<bool>>
{public FormUCViewModel(){IsActive = true;}[ObservableProperty]private bool canAllow;public void Receive(PropertyChangedMessage<bool> message){if (message.PropertyName == nameof(ListUCViewModel.IsAdd)){CanAllow = message.NewValue;} }}
xaml
<Button Grid.Row="3"Content="存入列表"Height="40"IsEnabled="{Binding CanAllow}"Command="{Binding AddButtonClickCommand}"Width="100" />
传递普通的值
点击按钮,把信息传入listbox
表单代码
public partial class FormUCViewModel:ObservableRecipient
{[ObservableProperty][NotifyPropertyChangedRecipients]private string nameProperty;[ObservableProperty][NotifyPropertyChangedRecipients]private string classProperty;private string phoneProperty;public string PhoneProperty{get { return phoneProperty; }set {if (SetProperty(ref phoneProperty, value)){WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<string>(this, nameof(PhoneProperty), default, value));}}}[RelayCommand]void AddButtonClick(){Student student = new Student(NameProperty, ClassProperty, PhoneProperty);WeakReferenceMessenger.Default.Send(new ValueChangedMessage<Student>(student));}}
列表代码
public class ListUCViewModel: ObservableRecipient,IRecipient<ValueChangedMessage<Student>>
{public ListUCViewModel(){lists.Add(new Student("张三", "三班", "123123123"));lists.Add(new Student("李四", "四班", "534343434"));lists.Add(new Student("王五", "六班", "876453534"));lists.Add(new Student("赵六", "二班", "123645634"));IsActive = true;}public ObservableCollection<Student> lists { get; set; } = new ObservableCollection<Student>();public void Receive(ValueChangedMessage<Student> message){lists.Add(message.Value);}
}
依赖注入
安装包
Install-Package Microsoft.Extensions.Hosting
Install-Package Microsoft.Extensions.DependencyInjection
编写App.xaml.cs
public partial class App : Application
{public IHost _host;public App(){_host = Host.CreateDefaultBuilder().ConfigureServices((context, services) =>{services.AddTransient<FormUCViewModel>();services.AddTransient<ListUCViewModel>();services.AddTransient<MainWindowViewModel>();services.AddTransient<ReciverUCViewModel>();services.AddTransient<SenderUCViewModel>();services.AddTransient<HelloServe>();}).Build();}protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);var mainWindow = new MainWindow();var mainViewModel = _host.Services.GetRequiredService<MainWindowViewModel>();mainWindow.DataContext = mainViewModel;mainWindow.Show();}protected override void OnExit(ExitEventArgs e){base.OnExit(e);_host.Dispose();}
}
veiw界面更改数据上下文的引用方式
public partial class ListUC : UserControl
{public ListUC(){InitializeComponent();//this.DataContext=new ListUCViewModel();//修改为依赖注入的方式var app = Application.Current as App;if (app != null){var viewModel = app._host.Services.GetRequiredService<ListUCViewModel>();this.DataContext = viewModel;}}
}