wpf 当使用 RegionManager.RequestNavigate 方法添加视图时,有没有办法从 Prism 区域中删除视图(按名称)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18086195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any way to remove a view (by name) from a Prism region when the view was added using the RegionManager.RequestNavigate method?
提问by Timothy Schoonover
I am using Prismfor navigation in my WPF MVVM application. I register my view as follows.
我在 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");
I display this view as follows.
我显示这个视图如下。
_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.
);
Elsewhere in the application, I need to remove this view in an event handler; however, the following code returns an ArgumentNullException.
在应用程序的其他地方,我需要在事件处理程序中删除这个视图;但是,以下代码返回一个ArgumentNullException.
_regionManager.Regions["MyRegion"].Remove(
_regionManager.Regions["MyRegion"].GetView("MyView")
);
This indicates that the RequestNavigatemethod does not add MyViewto MyRegionusing the name "MyView". I know that if I were to use the _regionManager.Add(MyView, "MyView")method, the GetViewmethod would not return null. Unfortunately, RequestNavigatedoes not seem to handle the view name in the same way. Is there any way to remove a view (by name) from a region when the view was added using the RequestNavigatemethod?
这表明该RequestNavigate方法不会添加MyView到MyRegion使用名称“MyView”。我知道如果我要使用该_regionManager.Add(MyView, "MyView")方法,该GetView方法不会返回 null。不幸的是,RequestNavigate似乎没有以相同的方式处理视图名称。当使用该RequestNavigate方法添加视图时,有没有办法从区域中删除视图(按名称)?
采纳答案by bland
It stems from how you add your view, not with your removal. Previously askedanswered by adding the view fully, aka including the name.
它源于您添加视图的方式,而不是您的删除。以前通过完全添加视图来回答,也就是包括名称。
_regionManager.Regions["MyRegion"].Add(myView, "MyView");
So now you can do your retrieval and removal:
所以现在您可以进行检索和删除:
var theView = _regionManager.Regions["MyRegion"].GetView("MyView");
_regionManager.Regions["MyRegion"].Remove(theView);
Without defining name during Regions.Add()
在 Region.Add() 期间没有定义名称
In your View, define a property that is accessible (public if multi-project, internal if all in one project). Use this property in everything, one example would be a public string ViewTitle { get { return "XYZ"; } }. Then retrieve from the Views the item that has the desired ViewTitle. The Views collection is the collection of views in that region, so you can use dynamic in .NET 4.0+ to ignore the type and get the property/function you specify, assuming it is there. Another option is to make your imported ViewModel in the View have a getter rather than just setting the DataContext, then you'd check the property "is" to the ViewModel you're looking for. Removes the string search but exposes the view's datacontext. So probably make an enum like I would do with the region.
在您的视图中,定义一个可访问的属性(如果是多项目则是公共属性,如果所有项目都在一个项目中则是内部属性)。在所有事情中都使用此属性,一个示例是公共字符串 ViewTitle { get { return "XYZ"; } }。然后从视图中检索具有所需视图标题的项目。Views 集合是该区域中的视图集合,因此您可以在 .NET 4.0+ 中使用 dynamic 来忽略类型并获取您指定的属性/函数,假设它在那里。另一种选择是让您在 View 中导入的 ViewModel 有一个 getter 而不是仅仅设置 DataContext,然后您将检查属性“is”到您正在寻找的 ViewModel。删除字符串搜索但公开视图的数据上下文。所以可能像我对这个地区做的那样做一个枚举。
I included everything in my View's .cs file so you can see how it works without complicating it or really breaking MVVM.
我将所有内容都包含在我的 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"; } }
}
Now in the ViewModel at some point:
现在在某个时候在 ViewModel 中:
var viewToRemove = RegionManager.Regions[RegionNames.WorkspaceTabRegion].Views.FirstOrDefault<dynamic>(v => v.ViewTitle == "AView");
RegionManager.Regions[RegionNames.WorkspaceTabRegion].Remove(viewToRemove);
回答by jnovo
We recently found ourselves with the same problem; thanks @odysseus.section9 for pointing its root in your comment, it really helped.
我们最近发现自己也遇到了同样的问题;感谢 @odysseus.section9 在您的评论中指出它的根源,它真的很有帮助。
We considered making all views implement an interface having a Name propertybut didn't feel quite right. Then we explored @bland solution but felt uncomfortable about using dynamic so we went for a very similar approach using reflection.
我们考虑过让所有视图都实现一个具有 Name 属性的接口,但感觉不太对。然后我们探索了@bland 解决方案,但对使用 dynamic 感到不舒服,所以我们使用反射采用了非常相似的方法。
Since we are also already using the ViewExportAttributeto export our views and it contains the desired ViewName property, what we do is querying for each view in a region for its attributes, looking for the ViewExportAttribute and checking the value of the ViewNameproperty. Although in our design all views are annotated with it, the query tolerates views that don't - it simply ignores them.
由于我们也已经使用ViewExportAttribute来导出我们的视图,并且它包含所需的 ViewName 属性,我们所做的是查询区域中每个视图的属性,查找 ViewExportAttribute 并检查ViewName属性的值。尽管在我们的设计中所有视图都用它进行了注释,但查询容忍没有注释的视图 - 它只是忽略它们。
For convenience we created an extension method for IRegion which searches for the views with the desired name within a region. Also, we added two extension methods to IRegionManager for two common scenarios in our application: re-using an existing view or navigating and removing all existing views (matching a name) and navigating. I think the latter solves your need just by getting rid of the call to
为方便起见,我们为 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));
}

