上一篇之分析了示例,沒有最終寫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>
最終運行的效果圖