最近这段时间一直在看一个开源软件PowerToys的源码,里面使用Modules的开发风格让我特别着迷,感觉比我现在写代码的风格好了太多太多。我尝试把PowerToys的架构分离了出来,但是发现代码维护量比较大,我自己很难维护这一套东西,就想到了同类型的Prism。
之前一直使用MVVMLight进行开发。因为最近要写一个开源的财务软件,想在项目中使用Prism,所以这个系列是财务软件的前置系列Prism从0到入门。主要是对照Prism官方例子去学一遍他的代码并整理成自己的代码。然后尝试理解Prism中体现的编程思想。以及如何在我们自己的项目中更好的使用Prism。
PrismLibrary/Prism-Samples-Wpf: Samples that demonstrate how to use various Prism features with WPF (github.com)
打开连接后有一个README.md。里面是Prism Samples WPF。1到29个示例包含了Prism的主要内容。这个系列我们就学习这个,并在学习完成后结合实践到自己的项目中。
一、浏览PrismSamples中的目录结构了解怎么学Prism;
简单浏览了一下,发现第07的Modules 分为了5种不同的方式,需要梳理的时间比较多,而01-06内容比较少,第一篇就先写到07之前,我们看到示例代码中BootstrapperShell(引导程序外壳)、Regions(区域)、CustomRegions(自定义区域)、ViewDiscovery (我理解为Register View WithRegion区域选项卡查看,把某个视图通过RegionManager放在某个位置)、ViewInjection(视图注入)、ViewActivationDeactivation(视图的激活和取消激活)。
现在开始学习示例代码。打开01BootstrapperShell的代码,我们进行观察;
1、App.xaml中主要修改
删掉了StartupUri属性,没有额外的代码。
2、App.cs中主要修改
App依然继承自Application,在重写OnStartup中实例化了Bootstrapper类,然后调用Bootstrapper实例后的对象的.Run()方法进行启动。
3、查看BootStrapper.cs
双击BootStrapper.cs打开源码看到了。包含了2个重写的方法CreateShell()方法返回一个DependencyObject。和一个没有返回值的RegisterTypes()方法。在学习WPF教程四的时候,我们讲到了DependencyObject对象,我们了解到DependencyObject所有的子对象都支持依赖项属性。包括UI控件。而CreateShell()方法返回的是一个DependencyObject类型,传入了Views文件夹下的MainWindow.xaml。
4、在MainWindow.xaml中主要变化
只有一个ContentControl,显示一串字符串"Hello from Prism"。
5、运行代码
发现打开了一个标题为Shell的窗体显示了Hello from Prism。就是我们的MainWindow。这里CreateShell()函数就是修改启动起始页面的地方。先不分析,继续看下一个Samples。
protected override Window CreateShell() { return Container.Resolve<MainWindow>(); }总结例子01:在CreateShell()中传入的MainWindow是设置默认启动页面,使用容器解析了MainWindw 并返回。(我们只学习代码,不考虑设计启动逻辑,单例等等。不在这里学习,只学Samples代码。)
观察02Regions示例;
1、App .xaml中主要修改
App.xaml中 添加命名空间
更换Application为prism:下的PrismApplication。
移除了StartupUri属性。
2、App.cs中主要修改
修改App继承自PrismApplication;
重写CreateShell()方法;
返回结果是使用Container.Resolve
protected override Window CreateShell() { return Container.Resolve<MainWindow>(); }Views下的MainWindow.xaml
创建了一个ContentControl控件,用于显示内容,并添加了附加依赖项属性prism:RegionManager.RegionName="ContentRegion" 。cs代码中无更新内容。
启动程序,界面无任何内容。
总结:在ContentControl控件中添加了附加依赖项属性,从命名看,是区域管理类下的区域名称设置为ContentRegion。
观察03CustomRegions示例;
1、App.xaml中主要修改
添加了
2、App.cs中主要修改
修改了App继承自PrismApplication。重写了CreateShell()方法,并且返回值修改为Window,同样使用了Container.Resolve
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings) { base.ConfigureRegionAdapterMappings(regionAdapterMappings); regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>()); }3、分析StackPanelRegionAdapter
我们看到StackPanelRegionAdapter是是在Prism文件夹。继承自RegionAdapterBase
一个公共的空的构造函数;
重写Adapt方法,并且传入了IRegion和StackPanel类型的参数,我们使用F12看到region.Views主要是获取区域中视图集合,所有添加视图的集合对象。这方法中使用传入的region.Views注册了CollectionChanged事件,这个事件主要是处理集合变更的消息;从这段代码看主要逻辑是传入的region如果集合发生了变化,如果是Add操作则把时间传入的控件添加到regionTarget中。
protected override void Adapt(IRegion region, StackPanel regionTarget) { region.Views.CollectionChanged += (s, e) => { if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { foreach (FrameworkElement element in e.NewItems) { regionTarget.Children.Add(element); } } //handle remove }; }一个CreateRegion()方法,F12看方法说明,是创建一个新的IRegion实例,用于调整对象。
protected override IRegion CreateRegion() { return new AllActiveRegion(); }3、Views 下的MainWindow.xaml
我们看到在MainWindow下有一个StackPanel。设置了一个附加依赖项属性,并命名为ContentRegion。cs文件中什么也没有新增。
<Grid> <StackPanel prism:RegionManager.RegionName="ContentRegion" /> </Grid>4、我们运行代码。界面什么也没有。
总结:这个例子在讲如何注册StakPanel,并通过在App下重写ConfigureRegionAdapterMappings()方法的方式,使用 regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve
观察04ViewDiscovery示例
1、App.xaml
添加命名空间
修改Application为prism:PrismApplication
去掉StartupUri属性
2、App.cs
重写CreateShell()方法。返回MainWindow。
protected override Window CreateShell() { return Container.Resolve<MainWindow>(); }3、Views下的MainWindow.xaml
添加了ContentControl控件,设置了附加依赖项属性 prism:RegionManager.RegionName="ContentRegion"
4、Views下的MainWindow.cs
再构造函数中,使用传入的regionManager使用RegisterViewWithRegion方法,传入了一个ContentRegion字符串,和ViewA。
public MainWindow(IRegionManager regionManager) { InitializeComponent(); //view discovery regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); }我们在RegisterViewWithRegion上F12看注释,通过注册类型将视图与区域相关联。当显示区域get时,将使用ServiceLocator将此类型解析为一个具体实例。实例将被添加到区域的视图集合中,两个参数分别是与视图关联的区域的名称,要注册到的视图的类型;
我就知道了,这里原来时使用regionMananger去注册关联一个区域名称,和一个视图对象。ContentRegion字符串是我们的ContentControl控件的附加依赖项属性,ViewA是我们的一个UserControl。
4、View下的ViewA.xaml
包含了一个38号大的字体显示内容为View A的TextBlock控件。CS文件中没有更改。
5、运行程序
界面上显示了View A。
总结:App启动时通过重写CreateShell()方法使用Container.Resolve方法返回一个MainWindow;MainWindow界面有一个ContentControl显示控件,有一个附加依赖项属性,设置了区域名称为ContentRegion。在MainWindow的有参构造函数中使用区域管理器,注册了视图和显示区域的关联,传入了区域名称和视图类。视图类是自己的显示内容。通过这样的流程在MainWindow下通过RegisterViewWithRegion方法,关联了具有ContenRegion名称的附加依赖项属性和视图类,界面上就显示了关联的视图。
观察05ViewInjection示例
1、App.xaml
添加了
修改Application为prism:PrismApplication。
去掉StartupUri属性
2、App.cs
App继承自PrismApplication
重写了CreateShell()方法,返回对象为Container.Resolve
3、Views下的MainWindow.xaml
创建了DockPanel ,设置最后一个元素填充剩余空间。创建Button按钮,填充在DockPanel面板的顶部,显示为Add View,创建Click事件,创建了ContentControl显示控件,设置附加依赖项属性RegionName,名字叫做ContentRegion。
<DockPanel LastChildFill="True"> <Button DockPanel.Dock="Top" Click="Button_Click">Add View</Button> <ContentControl prism:RegionManager.RegionName="ContentRegion" /> </DockPanel>4、Views下的MainWindow.cs
使用F12跳转到对应的接口说明
IContainerExtension _container 对象是对容器的抽象。
IRegionManager _regionManager; 是定义一个接口来管理一组区域并将区域附着到对象;
构造函数中初始化了这2个对象,使用是在这个Button的点击事件中,我们看到了使用容器对象Resolve解析了ViewA界面,然后使用了IRegionManager对象找到了在XAML中定义的附加依赖项属性名为ContentRegion的控件,然后使用Add方法添加了容器中的ViewA
public partial class MainWindow : Window { IContainerExtension _container; IRegionManager _regionManager; public MainWindow(IContainerExtension container, IRegionManager regionManager) { InitializeComponent(); _container = container; _regionManager = regionManager; } private void Button_Click(object sender, RoutedEventArgs e) { var view = _container.Resolve<ViewA>(); IRegion region = _regionManager.Regions["ContentRegion"]; region.Add(view); } }5、Views下的ViewA.xaml
是一个UserControl,里面只有一个TextBlock 显示内容为View A 字号为38。cs文件中没有额外的东西。
6、运行代码,界面显示View A
总结:在程序启动时更改Application类为PrismApplication,在重写CreateShell()方法时使用Container解析MainWindow窗体,并返回,作为启动窗体,在MainWindow被启动时,在构造函数中初始化了容器接口和区域管理对象。MainWindow界面中设置了显示控件和点击控件、显示控件设置了附加依赖项属性,用于做区域名称ContentRegion。在点击事件中,使用容器接口解析ViewA用户控件,并使用区域管理器查找名字为ContentRegion的区域(我们界面上的ContentControl),然后再调用这个区域返回对象的Add方法再找到的这个区域中显示我们刚才解析的ViewA自定义控件。
观察06ViewActivationDeactivation示例
1、App.xaml
替换Application为PrismApplication,使用Prism框架的时候,我看到现在每个都替换了。所以这一部分后面再写到的时候我都...处理。
(和前面一样的部分我就省略了)
2、App.cs
重写CreateShell(),解析MainWindow并返回,作为启动页面。
(....)
3、MainWindow.xaml
创建DockPanel,用StackPanel嵌套4个Button,并 设置了显示控件ContenControl,添加附加依赖属性RegionName为ContentRegion。Button 从名字理解,主要是激活ViewA (Button_Click)取消激活ViewA(Button_Click_1);激活ViewB(Button_Click_2) 取消激活ViewB(Button_Click_3)。
<DockPanel LastChildFill="True"> <StackPanel> <Button Content="Activate ViewA" Click="Button_Click"/> <Button Content="Deactivate ViewA" Click="Button_Click_1"/> <Button Content="Activate ViewB" Click="Button_Click_2"/> <Button Content="Deactivate ViewB" Click="Button_Click_3"/> </StackPanel> <ContentControl prism:RegionManager.RegionName="ContentRegion" HorizontalAlignment="Center" VerticalAlignment="Center" /> </DockPanel>4、Views下的MainWindow.cs
定义了变量容器接口对象,区域管理对象,区域对象和两个ViewA、ViewB页面对象;
构造函数中初始化了容器接口和区域管理对象、注册了loaded事件;
再Loaded事件中,使用容器解析ViewA和ViewB并放入类的ViewA和ViewB对象;
使用区域管理器获取界面上的ContentRegion区域对象,复制给类的_region对象,并再区域中添加ViewA和ViewB视图;
Button下4个Click使用_region的Activate和Deactivate方法显示对应的ViewA和ViewB;
private void Button_Click(object sender, RoutedEventArgs e) { //activate view a _region.Activate(_viewA); } private void Button_Click_1(object sender, RoutedEventArgs e) { //deactivate view a _region.Deactivate(_viewA); } private void Button_Click_2(object sender, RoutedEventArgs e) { //activate view b _region.Activate(_viewB); } private void Button_Click_3(object sender, RoutedEventArgs e) { //deactivate view b _region.Deactivate(_viewB); }5、Views下的ViewA.xaml和ViewB.xaml无特殊代码,就是显示对应的ViewA和ViewB;
6、运行代码,点击不同的Button可以切换显示ViewA和ViewB,
总结:MainWindow在构造函数中初始化了容器接口和区域管理对象,
在loaded事件中初始化了用于显示的容器解析对象ViewA和ViewB,使用区域管理区查找我们在界面上通过附加依赖项属性定义的ContentRegion显示控件,并返回给一个IRegion区域对象,使用IRegion区域对象的Add方法,添加资源到区域中。
在4个Button的Click事件中,主要......
原文转载:http://www.shaoqun.com/a/875539.html
跨境电商:https://www.ikjzd.com/
邮乐购物商城:https://www.ikjzd.com/w/1776
慧聪商务网:https://www.ikjzd.com/w/1836
斑马物联网:https://www.ikjzd.com/w/1316
最近这段时间一直在看一个开源软件PowerToys的源码,里面使用Modules的开发风格让我特别着迷,感觉比我现在写代码的风格好了太多太多。我尝试把PowerToys的架构分离了出来,但是发现代码维护量比较大,我自己很难维护这一套东西,就想到了同类型的Prism。之前一直使用MVVMLight进行开发。因为最近要写一个开源的财务软件,想在项目中使用Prism,所以这个系列是财务软件的前置系列Pr
易麦:https://www.ikjzd.com/w/2048
dmm杂志:https://www.ikjzd.com/w/2026
去淡水老街应该如何乘车:http://www.30bags.com/a/419462.html
去到泰国住酒店,出门前放枕头边20泰铢,回来会有惊喜!:http://www.30bags.com/a/277406.html
去稻城亚丁吃什么? :http://www.30bags.com/a/411103.html
去稻城亚丁旅游多少钱,稻城亚丁旅游费用:http://www.30bags.com/a/426016.html
校花的腿张来让男生桶 我把班花桶到深处:http://lady.shaoqun.com/a/247638.html
强壮公的侵犯让我次次高潮 强壮的公么征服了我:http://lady.shaoqun.com/m/a/247592.html
深圳花橙摩登卡有效期多久:http://www.30bags.com/a/500682.html
深圳眼界展览有月壤吗:http://www.30bags.com/a/500692.html
亚马逊新卖家新产品没有review怎么办?:https://www.ikjzd.com/articles/146612
煤炉Mercari平台真的很好做吗?物流收款怎么解决?:https://www.ikjzd.com/articles/146611
No comments:
Post a Comment