【Prism系列】Region的用法
前言
Prism中的Region可以和WPF中提供的Frame进行类比,Frame通过加载不同的Page达到界面导航的效果。Region也有相同的作用,不过Region有Psrim框架以及容器的加持,能够支持更细致化的导航控制,更轻松的传参, 更方便的生命周期管理,以及提供更加松的耦合,等等。Region的整个套路和上一篇文章《Prism子窗口实现》有着很多共同之处,大家可以对照学习。
注册与注入
和上篇一样,我们准备几个用户控件用来充当导航的内容。同样准备的内容,我们可以提前注册到容器中。上篇中我们使用:containerRegistry.RegisterDialog<MyDialog>(); 注册了子窗口,这次我们使用 containerRegistry.RegisterForNavigation<MyDialog>(); 将MyDialog整个控件注册成导航需要的界面。不过这次为了导航效果再准备一个叫MyView的控件。
讲《Prism子窗口实现》的时候,Prism为我们准备了IDialogService管理窗口。同样的Prism也为我们提供了一个叫IRegionManager的对象管理Region。这里我们可以直接注入:
[Dependency]
public IRegionManager regionManager { get; set; }
前台区域划分
接下来,我们需要再前台画出一片区域,并且給这片区域起个名字:(xmlns:prism="http://prismlibrary.com/")
<ContentControl Grid.Row="1" Grid.Column="1" prism:RegionManager.RegionName="MainRegion"/>
这貌似就是给ContentControl添加了一个附加属性啊?为啥是ContentControl?这里涉及到Region适配器的相关内容,我这里暂且不表。现在只需理解为,ContentControl所在的这篇区域就是划分出来的Region,并且名字叫做MainRegion。
这里需要注意一个问题,Region区域需要定义到顶层Windows,如果定义到子界面比如Page中,会导致区域名称识别不到(即使通过RegisterViewWithRegion注册,切换界面也会有切换不了的问题)。
其实Region只需要存在于主界面,就能解决我们的所有需求,无非是多划分几个区域而已,并不需要嵌套。
关系建立
现在内容准备好了,区域也划分好了,现在需要讲内容和区域建立关系。
regionManager.RequestNavigate("MainRegion", "MyDialog");
MainRegion是区域的名字,MyDialog是要显示内容的类名称。
下面提供完整的测试代码:
<ContentControl Grid.Row="1" Grid.Column="1" prism:RegionManager.RegionName="MainRegion"/>
<StackPanel Grid.Row="1">
<Button Content="界面1" Command="{Binding BtnCommand}" CommandParameter="MyDialog"/>
<Button Content="界面2" Command="{Binding BtnCommand}" CommandParameter="MyView"/>
</StackPanel>
[Unity.Dependency]
public IRegionManager regionManager { get; set; }
public Region的用法ViewModel()
{
BtnCommand = new DelegateCommand<string>(Do);
}
void Do(string str)
{
regionManager.RequestNavigate("MainRegion", str);
}
测试效果:
Region适配器
首先要说明的是,RequestNavigate的是单例模式,相同的类只会往区域里添加一次。为了证明这一点,我们换一个适配器看看,之前我们用的是,ContentControl。现在换成ItemsControl试试:
<ScrollViewer Grid.Column="2" >
<ItemsControl prism:RegionManager.RegionName="MainRegion"/>
</ScrollViewer>
其余的不变,效果如下:
最明显的区别是,当 ContentControl换成ItemsControl后,切换界面,变成了添加了两个界面。
这个就是适配器带来的区别。
其实要注意是,不过切换多少次,最多只能添加两个。这就是RequestNavigate的单例的特性。
如果像添加多个,需要将RequestNavigate换成AddToRegion:
regionManager.AddToRegion("MainRegion", str);
效果如下:
从这里我们可以看到,RequestNavigate是用于单个界面的切换,通常和ContentControl配合使用。而AddToRegion是用于界面的添加,或者说是多个界面的嵌入,通常和ItemsControl配合使用。
其实将区域和内容建立关系的函数,除了RequestNavigate和AddToRegion,其实还有一个RegisterViewWithRegion。如果换成RegisterViewWithRegion,你会发现这个效果和AddToRegion是一模一样的。它和AddToRegion的区别在于,它额外包含注册部分,也就是之前再App中注册的部分可以省略掉:
containerRegistry.RegisterForNavigation<MyDialog>();
containerRegistry.RegisterForNavigation<MyView>();
适配器的种类
- ContentControlRegionAdapter: ContentControl
- ItemsControlRegionAdapter: ItemsControl
- SelectorRegionAdapter
- ComboBox
- ListBox
- Ribbon
- TabControl
也就是说,并不是任何的控件,都能最为区域,符合上述适配器的要求控件才能作为Region。
大家可以尝试不用控件作为区域会是什么效果,比如TabControl。后续随着研究的深入,我再进行内容的补充吧。
prism还停供了接口,让我们可以自定义适配器(暂时不去研究了)。
Region的生命周期
通过管理的界面,是有IOC加持的,所以有生命周期的概念,我们知道,每次当Page切换时,Page其实经历了Unload的和Load的过程,之前界面修改的内容,切换后都会被重置。
但是Region默认会被保存到IOC里(本质在内存中保存),所以切换界面,界面不会被重置。
但是,如果我们也可以让其切换后重置。只需要让控件界面对应的ViewModel实现接口IRegionMemberLifetime即可。这个接口里只有一个KeepAlive变量,将其置为false即可。
public bool KeepAlive => false;
//或者写成:
public bool KeepAlive { get; } = false;
导航确认
导航确认,就是跳转时可能会有几个步骤,prism框架提供几个回调,让我们的代码可以参与其中。让控件界面对应的ViewModel实现接口IConfirmNavigationRequest:
当我们调用RequestNavigate时,离开当前页面A会调用A的ConfirmNavigationRequest,确认是否离开,如确认离开,则继续调用A的OnNavigatedFrom,去到另外一个页面B,会调用B的IsNavigationTarget,表示返回一个新的界面还是IOC里已经有的,然后继续调用OnNavigatedTo表示已经来到B界面。
#region 导航确认
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
// 确认是否离开当前视图
bool result=true;
//if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No)
//{ result = false; }
//else
//{ result = true; }
continuationCallback(result);
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
//来到当前试图
var value = navigationContext.Parameters["value"];
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 当切换到本界面时:
// 当返回True的时候,返回容器里面的view
// 当返回 False的时候,返回一个新的view
// 和 KeepAlive时相同的意思
return ture;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 离开当前视图
}
#endregion
这里说明几个点:
ConfirmNavigationRequest:里面有个回调函数,调用时如果传true,表示可以跳转。如果为false表示不可以跳转。如果不调用这个回调,也无法跳转。
IsNavigationTarget:如果你是为了切换界面,这里IsNavigationTarget永远返回true,不要返回false。返回false会导致新的界面产生旧的还在,这样随着界面切换的次数增加,IsNavigationTarget被框架调用的次数随着增加,内存也变大。
如果你想返回一个新的界面,应该使用KeepAlive=>false ,这样不会导致该问题!
导航传参
在调用regionManager.RequestNavigate的时候,可以多传一个参数:
NavigationParameters para = new NavigationParameters();
para.Add("key", "any");
regionManager.RequestNavigate("MainRegion", "MyView", para);
那么在实现接口IConfirmNavigationRequest的函数里都有一个参数: navigationContext,
这个参数中就会包含RequestNavigate传进来的参数对象了:
最后,欢迎大家,点赞+关注。
作者:宋桓公
出处:http://www.cnblogs.com/douzi2/
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?