WPF Prism入门笔记
使用技术:Prism、ReactiveProperty
Prism项目创建
Prism项目创建有多重方式,这里列两种:
-
使用Prism Template Pack插件创建(
要求Visual Studio 2019以上,笔者在2017上没有找到这个插件
)
-
创建普通WPF程序,然后手动修改配置
Prism Template Pack插件创建(推荐)
在Visual Studio扩展中安装Prism Template Pack然后重启,创建项目中就有Prism项目,可以创建Prism Full App,如果不熟悉的话推荐创建Prism Blank APP,框架使用
.net Core
或者
.net Framework
都可以。
创建好就可以看到最基础的项目结构。
手动创建
创建一个普通WPF程序,然后在Nugget中添加Prism.Unity、ReactiveProperty两个引用。
删除APP.xaml中的StartUrl属性,添加prism属性:
xmlns:prism="http://prismlibrary.com/"
(
注意这里的网址最后要带上
/
),然后把跟标签
Application
修改为
prism:PrismApplication
App.xaml.cs不再继承Window类,并且提示需要实现RegisterTypes抽象方法,使用空实现即可。
创建文件夹
Views
、
ViewModels
,并在Views中创建一个测试用的Index窗口,Index.xaml中的跟标签需要添加
xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True"
两个属性;在ViewModels文件夹创建IndexViewModel类(public),继承BindableBase
在App.xaml.cs中重写CreateShell方法来设置起始页,把Index添加到Container中:
return Container.Resolve<Index>();
这样,prism就会自动把Views文件夹中的视图和ViewModels文件夹中的视图模型绑定起来。
同时还可以配置默认Views和ViewModels文件夹的名称、注册自定义ViewModel,详见
.NET Core 3 WPF MVVM框架 Prism系列之数据绑定
文章中的Text属性可以使用ReactiveProperty进行简化,绑定写作
{Binding Text.Value}
ReactiveProperty、ReactiveCommand的简单使用
ReactiveProperty可以看做一个响应式的绑定容器,不再需要手动去实现WPF中的INotifyPropertyChanged接口,同时还添加了一些Linq方法。
首先在xaml中添加一个文本框、一个按钮、一个单选框:
<StackPanel>
<!-- 绑定ReactiveProperty类型的属性时需要在后面加.Value -->
<TextBox Name="TextBox1" Height="23"
Text="{Binding Text1.Value}"/>
<!-- 如果不需要带参数,就不需要CommandParameter属性 -->
<Button Name="Button1"
Content="Button1"
Command="{Binding Button1Command}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"/>
<CheckBox Content="CheckBox"
IsChecked="{Binding IsChecked1.Value}"/>
</StackPanel>
然后在viewModel中加入如下属性:
// ReactiveProperty的泛型是存储值的类型
public ReactiveProperty<string> Text1 { get; } = new ReactiveProperty<string>();
// ReactiveCommand的泛型是参数的类型,比如上面Button1的CommandParameter将按钮自身作为参数传进来,如果不需要传参,可以不加泛型。
public ReactiveCommand<Button> Button1Command { get; } = new ReactiveCommand<Button>();
public ReactiveProperty<bool> IsChecked1 { get; } = new ReactiveProperty<bool>();
然后在viewModel的构造方法中添加command的响应处理:
Button1Command.Subscribe(btn => {
this.Text1.Value = DateTime.Now.ToString();
});
这样点击按钮就可以把当前时间显示在编辑框内
如果想要单选框选中的时候才能点击按钮,可以根据IsChecked1生成ReactiveCommand
Button1Command = IsChecked1.ToReactiveCommand<Button>();
Button1Command.Subscribe(btn => {
this.Text1.Value = DateTime.Now.ToString();
});
这样单选框未选中的状态,按钮将不能点击。
如果有两个单选框,需要根据这两个单选框的状态来判断按钮是否可点击,只需要这么写:
// 这个数据的类型是IObservable<bool>[]
Button1Command = new[] {
IsChecked1.Select(s => s),
IsChecked2.Select(s => s),
}.CombineLatest(s => s[0] && s[1]).ToReactiveCommand<Button>();
这样两个点选框都选中的时候按钮才能点击,并且这种是关系响应式的。
异步命令
ReactiveCommand的代码是同步执行的,如果执行时间过长,会阻塞UI线程,因此就可以使用异步command
例子:
AsyncCommand = new AsyncReactiveCommand();
AsyncCommand.Subscribe(async () => {
await Task.Run(() => {
Thread.Sleep(3000);
this.Text1.Value = "Async Test";
});
事件转命令
如果需要通过事件来执行命令,可以使用下面这种方式。
首先添加System.Windows.Interactivity的引用,并在xaml根标签中添加属性:
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
然后就可以添加第一个文本框:
<TextBox Name="TextBox2" Height="23"
Text="{Binding Text2.Value, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding Text2ChangeCommand}"
CommandParameter="{Binding ElementName=Button1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
然后在viewModel中声明一个Text2ChangeCommand属性即可。
对弈TextChange事件,会有一个TextChangedEventArgs参数,如果想要把这个参数是传给command,上述方法是不行的,可以使用prism提供的InvokeCommandAction,也就是把上述xml中的InvokeCommandAction修改为:
<prism:InvokeCommandAction Command="{Binding Text2ChangeCommand}"/>
如果只需要串EventArgs中的特定属性,比如触发该事件的名字,也就是父类RoutedEventArgs的Source属性,只需在标签上加如下属性:
<prism:InvokeCommandAction Command="{Binding Text2ChangeCommand}" TriggerParameterPath="Source"/>
标签:
C#
,
WPF
2024年 07月
2024年 04月
2024年 03月
2024年 02月
2024年 01月
2023年 12月
2023年 11月
2023年 10月
2023年 07月
2023年 06月
2023年 05月
2023年 04月
2023年 03月
2023年 02月
2023年 01月
2022年 09月
2022年 07月
2022年 06月
2022年 03月
2021年 12月
2021年 11月
2021年 10月
2021年 07月
2021年 04月
2021年 03月
2021年 02月
2021年 01月
2020年 12月
2020年 09月
2020年 04月
2020年 03月
2020年 02月
2020年 01月
2019年 10月
2019年 09月
2019年 08月
2019年 07月
2019年 06月
2019年 05月