这一篇是学习了前2篇RegionManager关联视图,和通过不同的方式加载Module示例之后的开始进入MVVM了。
从第08示例开始,进入了MVVM部分。
从08示例开始学习Prism下的MVVM思想
目录- 从08示例开始学习Prism下的MVVM思想
- 观察08-ViewModelLocator示例
- 1、分析ViewModelLocator工程
- 1.1、App.xaml
- 1.2、App.cs
- 1.3、Views下的MainWindow.xaml
- 1.4、ViewModels文件夹下的MainWindowVieModel.cs
- 2、运行代码
- 1、分析ViewModelLocator工程
- 分析09-ChangeConvention示例
- 1、ViewModelLocator工程
- 1.1、App.xaml
- 1.2、App.cs
- 1.3、Views下的MainWindow.xaml
- 1.4、Views下的MainWindowViewModel.cs
- 1.5、运行代码
- 1、ViewModelLocator工程
- 分析10-CustomRegistrations示例
- 1、Views下的MainWindow.xaml
- 2、ViewModels 下的CustomViewModel.cs
- 3、重写ConfigureViewModelLocator()
- 启动代码
- 分析11-CustomRegistrations示例
- 1、MainWindow.xaml
- 1.1、 我们来分析MainWindowViewModel.cs代码;
- 运行代码
- 1、MainWindow.xaml
- 分析12-UsingCompositeCommands示例
- 1、分析引用关系最小的UsingCompositeCommands.Core工程
- 1.1、新增ApplicationCommands.cs
- 2、分析相对简单逻辑内容较少的UsingCompositeCommands主工程;
- 2.1、App.Xaml
- 2.2、App.cs
- 2.3Views下的MainWindow.xaml
- 2.4ViewModels下的MainWindowViewModel.cs
- 3、分析ModuleA工程
- 3.1、ModuleAModule.cs
- 3.2、Views下TabView.xaml
- 3.3、ViewModels下的TabViewModel.cs
- 4、运行代码
- 1、分析引用关系最小的UsingCompositeCommands.Core工程
- 观察08-ViewModelLocator示例
- 我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085
观察08-ViewModelLocator示例
08示例只有一个工程,添加了Prism.Unity的包
1、分析ViewModelLocator工程
1.1、App.xaml
添加了命名空间
修改了Application为prism:PrismApplication
移出了StartupUri属性
1.2、App.cs
修改了App继承自PrismApplication
重写CreateShell()设置主页面
重写RegisterTypes()
1.3、Views下的MainWindow.xaml
添加了显示控件ContentControl并设置了附加依赖项属性,区域名称:ContentRegion
设置和Title{Binding Title}
设置了prism:ViewModelLocator.AutoWireViewModel="True" 属性。
cs文件下无新增代码
1.4、ViewModels文件夹下的MainWindowVieModel.cs
MainWindowViewModel继承自Prism.Mvvm.Bindable类,该类继承自INotifyPropertyChanged
并创建了属性Title并在Set的时候调用了SetProperty实现基于Bindable封装的属性通知。
2、运行代码
界面标题显示Prism Unity Application;
总结:在工程中引用Prism.Unity后,不需要额外去写DataContent代码,就可以自动关联ViewModel和View。ViewModel 又有封装比较好的BindableBase。只需要在VM下继承自BindableBase就可以了,至于如何关联上ViewModel和View的,这里还没有深入了解,只是分析示例,没有看到有额外配置的地方,凭经验MVC的经验,感觉是同名ViewModels和View。需要写代码验证;
分析09-ChangeConvention示例
ChangeConvention示例的工程名字为ViewModelLocator,只有一个工程,添加了对Prism.Unity包的引用
1、ViewModelLocator工程
1.1、App.xaml
添加了命名空间
修改了Application继承自prism:PrismApplication
移除了StartupURI属性
1.2、App.cs
重写了CreateShell(),使用Container.Resolve解析MainWindow作为返回主窗体
重写了ConfigureViewModelLocator()方法,主要的内容都在这里。把断点打 var viewName = viewType.FullName;这一行,我们观察在干什么,
protected override void ConfigureViewModelLocator() { base.ConfigureViewModelLocator(); ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) => { var viewName = viewType.FullName; var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName; var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}"; return Type.GetType(viewModelName); }); }
我们首先观察方法ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver()
F12跳转过去之后,从注释上理解是将默认视图类型设置为视图模型类型解析程序。
通过重写ConfigureViewModelLocator()方法,在这里重新关联View和ViewModel的关系。
通过上面的截图我们看到了ViewName、ViewModelName被重新做了关联,ViewModel被指定到了ViewModelLocator.Views.MainWindowViewModel。我们在Views目录下看到了MainWindowViewModel.cs。
1.3、Views下的MainWindow.xaml
设置了显示控件的ContentControl设置了RegionName为ContentRegion
设置了窗口的Title绑定{binding Title}
设置了Prism:ViewModelLocator.AutoWireViewModel="True"
cs文件中无修改
1.4、Views下的MainWindowViewModel.cs
继承自BindableBase。 创建了属性Ttile使用SetProperty进行属性更改通知。
1.5、运行代码
标题修改为Prism Unity Application
总结:这个Demo主要是在讲解在App.cs下重写ConfigureViewModelLocator()方法,重新设置了View和对应ViewModel的关联。一般情形下,这个应该用不到把,毕竟Views和ViewModels是2个独立的文件夹。
分析10-CustomRegistrations示例
经过了前面这么多例子的学习,现在开始加快进度,每个工程打开后我们都会梳理一遍工程,主要梳理工程引用关系、引用的包、加载启动项,后续的过程中如果没有额外需要注意的,那么梳理过程教程中就省略了,因为前面这么多例子下来,应该都知道关注哪些内容了。
1、Views下的MainWindow.xaml
prism:ViewModelLocator.AutoWireViewModel=True;
Title={binding Title}
添加ContentControl并设置了附加依赖项属性RegionName为ContentRegion,cs文件中无新增代码
2、ViewModels 下的CustomViewModel.cs
继承自Prism.Mvvm.BindableBase
创建属性Title 并在set中使用SetPriperty实现通知;
3、重写ConfigureViewModelLocator()
代码中提供了4种方法。
protected override void ConfigureViewModelLocator() { base.ConfigureViewModelLocator(); // type / type //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(CustomViewModel)); // type / factory //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<CustomViewModel>()); // generic factory //ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<CustomViewModel>()); // generic type ViewModelLocationProvider.Register<MainWindow, CustomViewModel>(); }
从代码中直观来看这四种都是实现一个事情的,第四种看上去最简洁,所以,我们用第四种,使用ViewModelLocationProvider类的Register关联2个对象。一个View、一个ViewModel。用于关联View和ViewModel。这种写法比上一个例子感觉优雅很多。
启动代码
界面Title正常显示在ViewModel中设置的Title属性为Custom ViewModel Application;
总结:在App.cs中重写ConfigureViewModelLocator()方法,使用ViewModelLocationProvider.Register自定义关联View和ViewModel的关系;
分析11-CustomRegistrations示例
工程引用Prism.Unity包;App.xaml继承自PrismApplication;App.cs重写CreateShell()设置启动窗体;
重点在MainWindow.xaml和MainWindowViewModel.cs
前面的示例学习我们知道了,Views和ViewModels文件夹内的同名View和ViewModel会在Prism下自动关联,不需要我们在ConfigureViewModelLocator()中从新绑定关系;也不需要写DataContent。
1、MainWindow.xaml
添加命名空间
添加附加依赖项属性:prism:ViewModelLocator.AutoWireViewModel=True
<Window x:
同时打开ViewModels下的MainWindowViewModel.cs,左右分屏对照着看,MainWindowViewModel继承自BindableBase;
在Xaml中CheckBox设置了IsChecked属性绑定了ViewModel下的IsEnabled属性,打开ViewModel下的IsEnabled属性发现在Set时不仅有SetProperty用于属性通知,还有一个ExecuteDelegateCommand.RaiseCanExecuteChanged()方法,暂且不管这里再干啥,我们继续向下看。因为这里有4种做一件事情的写法,我们可以了解四种,但是用一种就行;
Xaml中4个Button分别绑定了ExecuteDelegateCommand、DelegateCommandObservesProperty、DelegateCommandObservesCanExecute、ExecuuteGenericDelegateCommand 命名绑定的同时传入了CommandParameter参数为"Passed Parameter"。
有一个TextBlock 控件, Text绑定为ViewModel中的UpdateText;
1.1、 我们来分析MainWindowViewModel.cs代码;
MainWindowViewModel继承自BindableBase类,再set中使用SetProperty做属性更改通知;
该类定义了IsEnable属性和UpdateText属性;和4个DelegateCommand、
在构造函数中初始化了4个DelegateCommand、在初始化过程中,除了最后一个ExecuteGenericDelegateCommand方法需要传入一个参数,其他的都不需要,这4种写法,都包含了2个逻辑,一个是执行Command、另外一个是是否可以执行,就是CanExecute用于返回当前指令是否可用;
当点击Xaml的对应的Button的时候,就会触发对应的Command、我喜欢用第一种写法,拓展性比较好,也比较简单明了;
ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
需要注意的是下面这个
ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled);
这个Command在初始化的时候,需要传入一个参数,为字符串类型的。后面的都一样。调用一个方法,验证Command是否允许调用。
public MainWindowViewModel() { ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute); DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled); DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled); ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric).ObservesCanExecute(() => IsEnabled); } private void Execute() { UpdateText = $"Updated: {DateTime.Now}"; } private void ExecuteGeneric(string parameter) { UpdateText = parameter; } private bool CanExecute() { return IsEnabled; }
运行代码
显示了标题为Using DelegateCommand的窗体;对照前面的调用关系,和属性绑定关系,Prism下面如何在View和ViewModel中使用binding和Command,这里就不讲这2个细节了,第一个基础系列WPF讲过了。这里只往返观察一下View的代码和ViewModel的代码中Prism是如何使用的。尝试点击各个按钮,看代码都运行到哪里了。
总结:在Prism中使用binding还是比较方便的。保持Views和ViewModels的路径关系,在MainWindow中设置Prism:ViewModelLocator.AutoWireViewModel=True,就自动关联了2个路径下的View和ViewModel的关系;
然后就可以使用Binding等一系列内容拉,不需要写DataContent。Command和Binding的用于都一样,ViewModel下需要继承自BindableBase类,剩下的实现方法都一样了。主要是Prism帮忙封装了INotifyPropertyChanged 不需要自己在封装了。
分析12-UsingCompositeCommands示例
这个示例是写到现在终于遇到一个复杂的拉,包含3个工程我们来梳理一下引用关系
ModuleA工程引用Prism.Wpf包、UsingCompositeCommands.Core;
UsingCompositeCommands工程引用Prism.Unity包、ModuleA、UsingCompositeCommands.Core
UsingCompositeCommands.Core工程引用了Prism.Core
是不是有点多,这个代码慢慢来。因为这里包含了Command的使用,涉及到了MVVM。如果不熟悉MVVM的话。这里会有点懵,第一个WPF系列中这里有讲到,去翻我博客就好拉。
1、分析引用关系最小的UsingCompositeCommands.Core工程
UsingCompositeCommands.Core引用了Prism.Core,核心就在Prism.Core。
1.1、新增ApplicationCommands.cs
新建InterFace接口 起名为IApplicationCommands、里面定义了一个只读的Prism.Commands下的CompositeCommand复合命令;
新建ApplicationCommands类继承IApplicationCommands接口,并创建了属性SaveCommand;
整个Core就结束了。这里定义了接口IApplicationCommands和实现接口的ApplicationCommands;
具体怎么实现的我们不去关注,我们就关注,UsingCompositeCommands.Core工程引用了Prism.Core
我们先学如何使用;只有这么多代码。
using Prism.Commands;namespace UsingCompositeCommands.Core{ public interface IApplicationCommands { CompositeCommand SaveCommand { get; } } public class ApplicationCommands : IApplicationCommands { private CompositeCommand _saveCommand = new CompositeCommand(); public CompositeCommand SaveCommand { get { return _saveCommand; } } }}
2、分析相对简单逻辑内容较少的UsingCompositeCommands主工程;
因为UsingCompositeCommands.Core写的内容注意再主工程UsingCompositeCommands中使用了。
先讲这个,逻辑可以关联上,最后讲XAML上绑定的Commands;
UsingCompositeCommands引用了Prism.Unity包;
项目ModuleA;
项目UsingCompositeCommands.Core;
No comments:
Post a Comment