四、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的13示例
上一篇之分析了示例,没有最终写DEMO,把这一篇分析完,总结后一起写Prism下的MVVM例子。
这一篇开始分析从13示例开始,分析到MVVM主要部分结束然后写一个分析后的总结DEMO
添加一段新的内容:Prism中新的内容还是挺多的,之前的思路是一篇里面写好几个Prism的例子,过一遍示例的代码,过完所有的Prism也就学完了。结果到第13篇的时候,卡住我了,2天才解决完这一个示例,而且发现其实只是Prism的一个特性,这个Prism还是要慢慢学,不要着急。有可能他新的一个接口,只有很少的代码,但是实际上实际干了很多的事情。比如这一篇里实际就是在讲IActiveAware接口。关键参数只有2个。但是整整2天我才搞明白是怎么回事。最近工作上、家庭上的事情比较多,感觉太累了,但是我会调整好状态,坚持下去。
这一篇示例主要是分析IActiveAware;
从13示例继续学习Prism下的MVVM思想
分析13UsingCompositeCommands示例
1、引用关系
UsingCompositeCommands包含3个工程
1.1、ModuleA工程引用了Prism.Wpf包、UsingCompositeCommands.Core;
1.2、UsingCompositeCommands工程引用了Prism.Unity包、ModuleA项目、UsingCompositeCommands.Core
1.3、UsingCompositeCommands.Core引用了Prism.Core包
我们从引用关系最小的开始看,UsingCompositeCommands.Core
2、分析UsingCompositeCommands.Core工程
2.1、新增ApplicationComands.cs
创建了ApplicationCommands接口,包含了一个属性SaveCommand;
添加类,并继承自IApplicationCommands接口
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类将会进行以下行为:
- CanExecute。只有当所有的活动命令可以被执行时,才会返回true。非活动的命令将不会执行。
- Execute。执行处于活动状态的命令,非活动的命令不会执行。
通过在ViewModel中实现IActiveAware接口,在Region中的子View变成活动窗口或者非活动窗口时都会被通知。当子View状态改变时,只有当前处于活动状态的View下的ViewModel的Command才会被执行。
3、分析主工程UsingCompositeCommands
引用了Prism.Unity包;
引用了ModuleA;
引用了UsingCompositeCommands.Core;
3.1、App.xaml
添加命名空间:xmlns:prism="http://prismlibrary.com/";
修改Appication为prism:PrismApplication;
去掉StartupUri属性;
3.2、App.cs
重写CreateShell()方法设置启动窗体
重写RegisterTypes()
使用容器注入UsingCompositeCommands.Core中的IApplicationCommands,以便在ViewModel中使用;
重写ConfigureModuleCatalog()
使用代码加载ModuleA项目中的ModuleAModule;
3.3、Views下的MainWindow.xaml
关键部分:
添加命名空间xmlns:prism="http://prismlibrary.com/"
设置prism.ViewModelLocator.AutoWireViewModel=Ture
添加了TabControl控件,并设置了附加依赖项属性RegionName,用于设置关联View的显示区域。
添加了Button按钮,设置了Command为ViewModel下的ApplicationCommands.SaveCommand,ApplicationCommands是App.cs在启动是重写RegisterTypes()时注册的。cs中无新增代码
3.4、ViewModel下的MainWindowViewModel.cs
MaindowViewModel继承自BindableBase
创建了IApplicationCommands属性并构造函数中初始化IApplicationCommands,
4、分析ModuleA工程
ModuleA工程引用Prism.Wpf包;
引用UsingComoisuteCommands.Core;
4.1、ModuleAModule
ModuleAModule继承自IModule,
在OInitialized方法中,使用containerProvider关联了Region和View。用于在显示区域添加View
4.2、ViewModels下的TabViewModel.cs
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才会更新。
结合上一篇的内容我们写一个DEMO
打开12、13示例,我们先回忆一遍12、13示例在干什么。我们从逻辑关联最少的开始回忆道逻辑关联最多的。这里希望我们自己去回忆,想不起来了,在去看。
1.1 两个示例的UsingCompositeCommands.Core都引用了Prism.Core;
创建了IApplicationCommands和ApplicationCommands;
添加了2个CompsiteCommand,一个是不带参数的,一个是带参数true的。这个是配合Modules下的IactivateAware接口使用的,用于是是否只更新活动状态下的ViewModel的内容。Prism.Core的内容就结束了
1.2 两个UsingCompositeCommands.Modues都引用了Prism.Wpf和UsingCompositeCommands.Core;
ModuleAModule都继承自ImOdule 并重写了OnInitialized方法,在里面完成了Region跟View的关联,和初始化。Views和ViewModels通过在xaml中编写Prism.ViewModelLocator.AutoWrieViewModel=true实现自动关联,在ViewModel中通过构造函数传入了IApplicationCommands接口,创建_applicationCommands对象绑定并注册对应的事件,用于执行全局的Command。
1.3主工程UsingCompsiteCommands引用了Prism.Unity、ModuleA和UsingCompositeCommands.Core;
重写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代码;
我们结合12、13示例,创建一个有多个TabControl的显示页面,编写2个全局按钮功能,一个是全局的AllSave方法触发时所有页面更新、一个全局的CurrentSave方法触发时当前页面更新,子页面包含两个Textblock和一个Button,Textblock用于显示标题和当前时间,button用于触发更能当前时间。用于熟悉Command和IActiveAware实现不同的Command的逻辑执行。
PrismMvvmDemo.Core
引用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;
}
}
}
}
PrismMvvmDemo.Modules
引用了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());
}
}
}
PrismMvvmDemo.Runner 主工程
添加了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>
最终运行的效果图
我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085
四、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的13示例的更多相关文章
- 一、从GitHub浏览Prism示例代码的方式入门WPF下的Prism
最近这段时间一直在看一个开源软件PowerToys的源码,里面使用Modules的开发风格让我特别着迷,感觉比我现在写代码的风格好了太多太多.我尝试把PowerToys的架构分离了出来,但是发现代码维 ...
- 三、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的08-12示例
这一篇是学习了前2篇RegionManager关联视图,和通过不同的方式加载Module示例之后的开始进入MVVM了. 从第08示例开始,进入了MVVM部分. 从08示例开始学习Prism下的MVVM ...
- 二、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Modules的几种加载方式
这一篇梳理Prism中07示例Module的几种加载方式. 07示例分为了5个,有5种不同的Module加载方式. 我们开始学习加载Modules 观察07-Modules-Appconfig示例 分 ...
- 五、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之MVVM中的EventAggregator
这一篇我们主要再看完示例12.13后,写了个例子,用于再Modules下执行ApplicationCommands,使用IActiveAware执行当前View的Commands,或者Applicat ...
- 用git从github网站上下载代码的方式
原本单击如下下载按钮即可 但有时候github异常,该按钮无效,可以使用如下方法: 1.复制url,如https://github.com/ulli-kroll/mt7610u 2.进入要存放该代码的 ...
- AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...
- 《ArcGIS Runtime SDK for Android开发笔记》——(7)、示例代码arcgis-runtime-samples-android的使用
1.前言 学习ArcGIS Runtime SDK开发,其实最推荐的学习方式是直接看官方的教程.示例代码和帮助文档,因为官方的示例一般来说都是目前技术最新,也是最详尽的.对于ArcGIS Runtim ...
- 2018-06-20 中文代码示例视频演示Python入门教程第三章 简介Python
知乎原链 Python 3.6.5官方入门教程中示例代码汉化后演示 对应在线文档: 3. An Informal Introduction to Python 不知如何合集, 请指教. 中文代码示例P ...
- pyspider示例代码:解析JSON数据
pyspider示例代码官方网站是http://demo.pyspider.org/.上面的示例代码太多,无从下手.因此本人找出一下比较经典的示例进行简单讲解,希望对新手有一些帮助. 示例说明: py ...
随机推荐
- .NET Core/.NET5/.NET6 开源项目汇总10:实用工具
系列目录 [已更新最新开发文章,点击查看详细] 开源项目是众多组织与个人分享的组件或项目,作者付出的心血我们是无法体会的,所以首先大家要心存感激.尊重.请严格遵守每个项目的开源协议后再使用.尊 ...
- js jq计算器
<html><head><meta http-equiv="Content-type" content="text/html; charse ...
- excel VBA使用教程
1.选择文件--选项 2.选择自定义功能区--开发工具的√勾上
- python之list列表(基础篇)
特点:1.有序的 2.可以存放多个元素 3.每个元素可以是任何数据类型,4,通过下标值访问1,定义一个空列表 2,定义一个非空列表 3.访问列表中的元素(同str类型) 4,切片与步长(同str类型 ...
- ECS实例中的应用偶尔出现丢包现象并且内核日志(dmesg)存在“kernel: nf_conntrack: table full, dropping packet”的报错信息
问题描述 连接ECS实例中的应用时偶尔出现丢包现象.经排查,ECS实例的外围网络正常,但内核日志(dmesg)中存在"kernel: nf_conntrack: table full, dr ...
- 13、mysql主从复制原理解析
13.1.mysql主从复制介绍: 1.普通文件,磁盘上的文件的同步方法: (1)nfs网络文件共享可以同步数据存储: (2)samba共享数据: (3)ftp数据同步: (4)定时任务:cronta ...
- AcWing 903. 昂贵的聘礼
年轻的探险家来到了一个印第安部落里. 在那里他和酋长的女儿相爱了,于是便向酋长去求亲. 酋长要他用10000个金币作为聘礼才答应把女儿嫁给他. 探险家拿不出这么多金币,便请求酋长降低要求. 酋长说:& ...
- Pandas高级教程之:GroupBy用法
Pandas高级教程之:GroupBy用法 目录 简介 分割数据 多index get_group dropna groups属性 index的层级 group的遍历 聚合操作 通用聚合方法 同时使用 ...
- pdfkit html转pdf
pdfkit的通用option选项 参考:https://cloud.tencent.com/developer/ask/202116https://www.cnblogs.com/taceywong ...
- 元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,typeHandlers?
报错主要部分如下: Error building SqlSession.### Cause: org.apache.ibatis.builder.BuilderException: Error cre ...