当使用 RegionManager.RequestNavigate 方法添加视图时,有啥方法可以从 Prism 区域中删除视图(按名称)?
Posted
技术标签:
【中文标题】当使用 RegionManager.RequestNavigate 方法添加视图时,有啥方法可以从 Prism 区域中删除视图(按名称)?【英文标题】:Is there any way to remove a view (by name) from a Prism region when the view was added using the RegionManager.RequestNavigate method?当使用 RegionManager.RequestNavigate 方法添加视图时,有什么方法可以从 Prism 区域中删除视图(按名称)? 【发布时间】:2013-08-07 19:33:22 【问题描述】:我在我的 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
方法添加视图时,有什么方法可以从区域中删除视图(按名称)?
【问题讨论】:
在深入了解 Prism 源代码后,RequestNavigate
似乎最终调用了region.Add(view);
(在RegionNavigationContentLoader.LoadContent
中下降)。所以就目前而言,我认为我想做的事情是不可能的。我认为可以通过使用用于指定视图名称的附加参数重载各种RequestNavigate
方法和扩展来实现此功能。这将允许通过名称访问已使用 RequestNavigate
添加到区域的视图。
我已将您的场景明确添加到我的答案中。
【参考方案1】:
它源于您添加视图的方式,而不是您的删除。 Previously asked 通过完整添加视图来回答,也就是包括名称。
_regionManager.Regions["MyRegion"].Add(myView, "MyView");
所以现在你可以进行检索和删除了:
var theView = _regionManager.Regions["MyRegion"].GetView("MyView");
_regionManager.Regions["MyRegion"].Remove(theView);
Regions.Add() 期间没有定义名称
在您的视图中,定义一个可访问的属性(如果是多项目,则为公共,如果在一个项目中,则为内部)。在所有内容中使用此属性,一个示例是公共字符串 ViewTitle get return "XYZ"; 。然后从 Views 中检索具有所需 ViewTitle 的项目。 Views 集合是该区域中视图的集合,因此您可以在 .NET 4.0+ 中使用 dynamic 来忽略类型并获取您指定的属性/功能,假设它在那里。另一种选择是让 View 中导入的 ViewModel 有一个 getter,而不仅仅是设置 DataContext,然后你会检查你正在寻找的 ViewModel 的属性“is”。删除字符串搜索但公开视图的数据上下文。所以可能像我对区域做的那样做一个枚举。
我将所有内容都包含在我的 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);
【讨论】:
是的,但我的问题是关于RequestNavigate
方法。如果您阅读我的评论,您会明白为什么这是不可能的。
@odysseus.section9 已编辑以包含此部分。
第二个建议实际上适用于RequestNavigate
!
@odysseus.section9 只需确保每个视图都包含您在 lambda 表达式中定义的任何内容,无论是属性、函数还是字段。否则,您将抛出异常并退出 LINQ 搜索而没有结果。至少,适用于您要搜索的区域中的任何视图。【参考方案2】:
我们最近发现自己遇到了同样的问题;感谢@odysseus.section9 在您的评论中指出它的根源,它真的很有帮助。
我们考虑过making all views implement an interface having a Name property,但感觉不太对劲。然后我们探索了@bland 解决方案,但对使用动态感到不舒服,因此我们采用了一种非常相似的方法,使用 reflection。
由于我们也已经在使用 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));
【讨论】:
以上是关于当使用 RegionManager.RequestNavigate 方法添加视图时,有啥方法可以从 Prism 区域中删除视图(按名称)?的主要内容,如果未能解决你的问题,请参考以下文章