当使用RegionManager.RequestNavigate方法添加视图时,是否有任何方法可以从Prism区域中删除
本文关键字:方法 任何 Prism 删除 区域 RegionManager RequestNavigate 添加 视图 是否 | 更新日期: 2023-09-27 18:26:35
我在WPF MVVM应用程序中使用Prism进行导航。我的看法如下。
// MyView is the data type of the view I want to register and "MyView"
// is the name by which I want the data type to be identified within
// the IoC container.
_container.RegisterType<object, MyView>("MyView");
我将此视图显示如下。
_regionManager.RequestNavigate(
"MyRegion", // This is the name of the Region where the view should be displayed.
"MyView" // This is the registered name of the view in the IoC container.
);
在应用程序的其他地方,我需要在事件处理程序中删除此视图;但是,下面的代码返回一个ArgumentNullException
。
_regionManager.Regions["MyRegion"].Remove(
_regionManager.Regions["MyRegion"].GetView("MyView")
);
这表示RequestNavigate
方法不会使用名称"MyView"将MyView
添加到MyRegion
。我知道如果我使用_regionManager.Add(MyView, "MyView")
方法,GetView
方法不会返回null。不幸的是,RequestNavigate
似乎没有以相同的方式处理视图名称。当使用RequestNavigate
方法添加视图时,是否有任何方法可以从区域中删除视图(按名称)?
它源于如何添加视图,而不是删除视图。之前的问题通过添加完整的视图来回答,也就是包括名称。
_regionManager.Regions["MyRegion"].Add(myView, "MyView");
所以现在你可以进行检索和删除:
var theView = _regionManager.Regions["MyRegion"].GetView("MyView");
_regionManager.Regions["MyRegion"].Remove(theView);
在Regions.Add()过程中未定义名称
在视图中,定义一个可访问的属性(如果是多个项目,则为公共属性;如果是一个项目中的所有属性,则为内部属性)。在所有内容中都使用此属性,例如公共字符串ViewTitle{get{return"XYZ";}}。然后从视图中检索具有所需ViewTitle的项目。Views集合是该区域中视图的集合,因此您可以在.NET 4.0+中使用dynamic来忽略类型并获取您指定的属性/函数(假设它在那里)。另一种选择是使视图中导入的ViewModel具有getter,而不仅仅是设置DataContext,然后将属性"is"检查为要查找的ViewModel。删除字符串搜索,但公开视图的数据上下文。所以可能会做一个枚举,就像我对这个区域所做的那样。
我在View的.cs文件中包含了所有内容,这样您就可以看到它是如何工作的,而不会使它复杂化或真正破坏MVVM。
[ViewSortHint("050")]
[ViewExport(RegionName = RegionNames.WorkspaceTabRegion)]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class AView : UserControl
{
public AView()
{
InitializeComponent();
}
[Import]
[SuppressMessage("Microsoft.Design", "CA1044:PropertiesShouldNotBeWriteOnly", Justification = "MEF requires property; never retrieved")]
PrintingViewModel ViewModel { set { this.DataContext = value; } }
public string ViewTitle { get { return "AView"; } }
}
现在在ViewModel中的某个时刻:
var viewToRemove = RegionManager.Regions[RegionNames.WorkspaceTabRegion].Views.FirstOrDefault<dynamic>(v => v.ViewTitle == "AView");
RegionManager.Regions[RegionNames.WorkspaceTabRegion].Remove(viewToRemove);
我们最近发现自己也遇到了同样的问题;感谢@odysseus.section9在您的评论中指出了它的根源,它真的很有帮助。
我们曾考虑让所有视图实现一个具有Name属性的接口,但感觉不太好。然后我们探索了@bland解决方案,但对使用dynamic感到不舒服,所以我们采用了非常类似的方法,使用反射。
由于我们已经在使用ViewExportAttribute导出视图,并且它包含所需的ViewName属性,因此我们要做的是在一个区域中查询每个视图的属性,查找ViewExportAttribute并检查ViewName属性的值。尽管在我们的设计中,所有视图都用它进行了注释,但查询可以容忍没有注释的视图——它只是忽略了它们。
为了方便起见,我们为IRegion创建了一个扩展方法,用于搜索区域内具有所需名称的视图。此外,我们为应用程序中的两种常见场景向IRegionManager添加了两种扩展方法:重新使用现有视图或导航并删除所有现有视图(匹配名称)和导航。我认为后者只需取消对的呼叫即可解决您的需求
public static IEnumerable<object> FindViews(this IRegion region, string viewName)
{
return from view in region.Views
from attr in Attribute.GetCustomAttributes(view.GetType())
where attr is ViewExportAttribute && ((ViewExportAttribute)attr).ViewName == viewName
select view;
}
public static void ActivateOrRequestNavigate(this IRegionManager regionManager, string regionName, string viewName, UriQuery navigationParams)
{
IRegion region = regionManager.Regions[regionName];
object view = region.FindViews(viewName).FirstOrDefault();
if (view != null)
region.Activate(view);
else
regionManager.RequestNavigate(regionName,
new System.Uri(navigationParams != null ? viewName + navigationParams.ToString() : viewName, UriKind.Relative));
}
public static void RemoveAndRequestNavigate(this IRegionManager regionManager, string regionName, string viewName, UriQuery navigationParams)
{
IRegion region = regionManager.Regions[regionName];
foreach (object view in region.FindViews(viewName))
region.Remove(view);
regionManager.RequestNavigate(regionName,
new System.Uri(navigationParams != null ? viewName + navigationParams.ToString() : viewName, UriKind.Relative));
}