上一篇之分析了示例,没有最终写DEMO,把这一篇分析完,总结后一块儿写Prism下的MVVM例子。express
这一篇开始分析从13示例开始,分析到MVVM主要部分结束而后写一个分析后的总结DEMOc#
添加一段新的内容:Prism中新的内容仍是挺多的,以前的思路是一篇里面写好几个Prism的例子,过一遍示例的代码,过完全部的Prism也就学完了。结果到第13篇的时候,卡住我了,2天才解决完这一个示例,并且发现其实只是Prism的一个特性,这个Prism仍是要慢慢学,不要着急。有可能他新的一个接口,只有不多的代码,可是实际上实际干了不少的事情。好比这一篇里实际就是在讲IActiveAware接口。关键参数只有2个。可是整整2天我才搞明白是怎么回事。最近工做上、家庭上的事情比较多,感受太累了,可是我会调整好状态,坚持下去。app
这一篇示例主要是分析IActiveAware;mvvm
UsingCompositeCommands包含3个工程ide
咱们从引用关系最小的开始看,UsingCompositeCommands.Core函数
建立了ApplicationCommands接口,包含了一个属性SaveCommand;学习
添加类,并继承自IApplicationCommands接口this
public class ApplicationCommands : IApplicationCommands { private CompositeCommand _saveCommand = new CompositeCommand(true); public CompositeCommand SaveCommand { get { return _saveCommand; } } }
这里和12例子有一个明显的差异,在初始化_SaveCommand的时候new CompositeCommand(true),传入了True。这里比较重要, 这里使用F12能够看到参数monitorCommandActivity,传入这个参数为True时,CompositeCommand类将会进行如下行为:spa
经过在ViewModel中实现IActiveAware接口,在Region中的子View变成活动窗口或者非活动窗口时都会被通知。当子View状态改变时,只有当前处于活动状态的View下的ViewModel的Command才会被执行。调试
引用了Prism.Unity包;
引用了ModuleA;
引用了UsingCompositeCommands.Core;
添加命名空间:xmlns:prism="http://prismlibrary.com/";
修改Appication为prism:PrismApplication;
去掉StartupUri属性;
重写CreateShell()方法设置启动窗体
重写RegisterTypes()
使用容器注入UsingCompositeCommands.Core中的IApplicationCommands,以便在ViewModel中使用;
重写ConfigureModuleCatalog()
使用代码加载ModuleA项目中的ModuleAModule;
关键部分:
添加命名空间xmlns:prism="http://prismlibrary.com/"
设置prism.ViewModelLocator.AutoWireViewModel=Ture
添加了TabControl控件,并设置了附加依赖项属性RegionName,用于设置关联View的显示区域。
添加了Button按钮,设置了Command为ViewModel下的ApplicationCommands.SaveCommand,ApplicationCommands是App.cs在启动是重写RegisterTypes()时注册的。cs中无新增代码
MaindowViewModel继承自BindableBase
建立了IApplicationCommands属性并构造函数中初始化IApplicationCommands,
ModuleA工程引用Prism.Wpf包;
引用UsingComoisuteCommands.Core;
ModuleAModule继承自IModule,
在OInitialized方法中,使用containerProvider关联了Region和View。用于在显示区域添加View
TabViewModel继承自BindableBase和IActiveAware。
就是这个IActiveAware卡了我两天。
其余的地方不讲,跟12示例同样,就讲13示例里不同的。
看属性IsActive。在Set时触发了OnIsActiveChanged()
根据调试时的状况。当只点击一个TabView的时候,IsActive只触发一次,第二次点击的时候,有2个IsActive进入两次,点击第三个的时候有3个。
bool _isActive; public bool IsActive { get { return _isActive; } set { _isActive = value; OnIsActiveChanged(); } } private void OnIsActiveChanged() { UpdateCommand.IsActive = IsActive; IsActiveChanged?.Invoke(this, new EventArgs()); }
一直没搞明白后来F12跳转到了IActiveAware才明白,这个是用来控制活动View和ViewModel下的Command的。而决定这个是否工做的就是在UsingCompositeCommands.Core下的ApplicationCommands 在初始化_saveCommand字段时的true参数
private CompositeCommand _saveCommand = new CompositeCommand(true);
我在看明白后,尝试设置true为false,发现全部的View的Command都会执行了,
执行主工程下的Save时,3个TabView都会更新。而值为true的时候,只有处于激活状态的TabViewModel才会更新。
打开十二、13示例,咱们先回忆一遍十二、13示例在干什么。咱们从逻辑关联最少的开始回忆道逻辑关联最多的。这里但愿咱们本身去回忆,想不起来了,在去看。
建立了IApplicationCommands和ApplicationCommands;
添加了2个CompsiteCommand,一个是不带参数的,一个是带参数true的。这个是配合Modules下的IactivateAware接口使用的,用因而是否只更新活动状态下的ViewModel的内容。Prism.Core的内容就结束了
ModuleAModule都继承自ImOdule 并重写了OnInitialized方法,在里面完成了Region跟View的关联,和初始化。Views和ViewModels经过在xaml中编写Prism.ViewModelLocator.AutoWrieViewModel=true实现自动关联,在ViewModel中经过构造函数传入了IApplicationCommands接口,建立_applicationCommands对象绑定并注册对应的事件,用于执行全局的Command。
重写App为PrismApplication,重写CreteShell()方法,设置启动对象。
重写RegisterTypes()加载UsingCompsiteCommands.Core下的ApplicationCommands
重写ConfigureModuleCatalog()用于加载Module。
ViewModel中建立属性IApplicationCommands并在构造函数中初始化。
View的XAML中使用Prism.ViewModelLocator.AutoWireViewModel=true关联ViewModel
View的XAML中直接设置Command为本身ViewModel下的ApplicationCommands的方法,用于关联。
同时设置显示区域控件并设置Region属性,用于在Modules下关联显示内容。
回忆完以后,在继续向下看;若是没有,建议在回忆一遍,接下来咱们结合12 13示例,开始写DEMO代码;
咱们结合十二、13示例,建立一个有多个TabControl的显示页面,编写2个全局按钮功能,一个是全局的AllSave方法触发时全部页面更新、一个全局的CurrentSave方法触发时当前页面更新,子页面包含两个Textblock和一个Button,Textblock用于显示标题和当前时间,button用于触发更能当前时间。用于熟悉Command和IActiveAware实现不一样的Command的逻辑执行。
引用Prism.Core、添加IApplicationCommands接口,编写2个保存的Command
using Prism.Commands; namespace PrismMvvmDemo.Core { public interface IApplicationCommands { CompositeCommand AllSave { get; } CompositeCommand CurrentSave { get; } } public class ApplicationCommands:IApplicationCommands { private CompositeCommand _allSave = new CompositeCommand(); public CompositeCommand AllSave { get { return _allSave; } } private CompositeCommand _currentSave = new CompositeCommand(true); public CompositeCommand CurrentSave { get { return _currentSave; } } } }
引用了Prism.Wpf、PrismMvvmDemo.Core
添加ModuleAModule 并继承自IModule,并在OnInitialized()方法中关联region和View。
ModuleAModule.cs的代码
添加3个TabView设置Title并关联到TabViewControlRegion显示区域。代码以下:尚未添加View和ViewModels,显示区域TabControlRegion也没有添加。
using Prism.Ioc; using Prism.Modularity; using Prism.Regions; using PrismMvvmDemo.Modules.ViewModels; using PrismMvvmDemo.Modules.Views; namespace PrismMvvmDemo.Modules { public class ModuleAModule : IModule { public void OnInitialized(IContainerProvider containerProvider) { var regionManager = containerProvider.Resolve<IRegionManager>(); var region = regionManager.Regions["TabControlRegion"]; var tabViewA = containerProvider.Resolve<TabView>(); SetTitle("TabViewA", tabViewA); region.Add(tabViewA); var tabViewB = containerProvider.Resolve<TabView>(); SetTitle("TabViewB", tabViewB); region.Add(tabViewB); var tabViewC = containerProvider.Resolve<TabView>(); SetTitle("TabViewC", tabViewC); region.Add(tabViewC); } public void RegisterTypes(IContainerRegistry containerRegistry) { } private void SetTitle(string title, TabView tabView) { (tabView.DataContext as TabViewModel).Title = title; } } }
再Modules下添加Views目录和ViewModels目录
Views下添加自定义控件TabView.xaml,主要设置Prism:ViewModelLocator.AutoWireViewModel=true
而后绑定CurrentTime、Binding UpdateTimeCommand。
<UserControl x:Class="PrismMvvmDemo.Modules.Views.TabView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:PrismMvvmDemo.Modules.Views" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <StackPanel> <TextBlock Text="当前时间:"/> <TextBlock Text="{Binding CurrentTime}"/> <Button Width="120" Height="30" Content="单击更新时间" Command="{Binding UpdateTimeCommand}"/> </StackPanel> </UserControl>
ViewModels下TabViewModel.cs代码,主要是继承自BindableBase和IActiveAware。经过构造函数绑定了ApplicationCommands并关联到了ViewModel下的Command。
using Prism; using Prism.Commands; using Prism.Mvvm; using PrismMvvmDemo.Core; using System; namespace PrismMvvmDemo.Modules.ViewModels { public class TabViewModel : BindableBase, IActiveAware { IApplicationCommands _applicationCommands; private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private bool _canUpdate = true; public bool CanUpdate { get { return _canUpdate; } set { SetProperty(ref _canUpdate, value); } } private string _currentTime = string.Empty; public string CurrentTime { get { return _currentTime; } set { SetProperty(ref _currentTime, value); } } public TabViewModel(IApplicationCommands applicationCommands) { _applicationCommands = applicationCommands; UpdateTimeCommand = new DelegateCommand(UpdateTime).ObservesCanExecute(() => CanUpdate); _applicationCommands.CurrentSave.RegisterCommand(UpdateTimeCommand); _applicationCommands.AllSave.RegisterCommand(UpdateTimeCommand); } private void UpdateTime() { CurrentTime = $"Update Time {DateTime.Now}"; } public event EventHandler IsActiveChanged; public DelegateCommand UpdateTimeCommand { get; private set; } private bool _isActive; public bool IsActive { get { return _isActive; } set { _isActive = value; OnIsActiveChanged(); } } private void OnIsActiveChanged() { UpdateTimeCommand.IsActive = IsActive; IsActiveChanged?.Invoke(this, new EventArgs()); } } }
添加了Prism.Unity的库,添加了PrismMvvmDemo.Core和PrismMvvmDemo.Modules两个库。
重写App.xaml 注意引用using Prism.Ioc;
<prism:PrismApplication x:Class="PrismMvvmDemo.Runner.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PrismMvvmDemo.Runner" xmlns:prism="http://prismlibrary.com/"> <Application.Resources> </Application.Resources> </prism:PrismApplication>
using Prism.Unity; using Prism.Ioc; using System.Windows; using Prism.Modularity; using PrismMvvmDemo.Core; using PrismMvvmDemo.Runner.Views; namespace PrismMvvmDemo.Runner { /// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { base.ConfigureModuleCatalog(moduleCatalog); moduleCatalog.AddModule<Modules.ModuleAModule>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>(); } } }
ViewModel建立MainWindowViewModel代码
using Prism.Mvvm; using PrismMvvmDemo.Core; namespace PrismMvvmDemo.Runner.ViewModels { public class MainWindowViewModel : BindableBase { private IApplicationCommands _applicationCommands; public IApplicationCommands ApplicationCommands { get { return _applicationCommands; } set { SetProperty(ref _applicationCommands, value); } } public MainWindowViewModel(IApplicationCommands applicationCommands) { _applicationCommands = applicationCommands; } } }
Views下的MainWindow.xaml代码。
<Window x:Class="PrismMvvmDemo.Runner.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <Style TargetType="TabItem"> <Setter Property="Header" Value="{Binding DataContext.Title}"/> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TabControl prism:RegionManager.RegionName="TabControlRegion"/> <StackPanel Grid.Row="1"> <Button Content="AllSave" Command="{Binding ApplicationCommands.AllSave}"/> <Button Content="CurrentSave" Command="{Binding ApplicationCommands.CurrentSave}"/> </StackPanel> </Grid> </Window>
最终运行的效果图