MEF:如何在离开视图时禁用绑定的重新评估
MEF: How can I disable reevaluation of bindings when leaving a view
我在 MEF 应用程序中遇到了一个有趣的情况。主工作区是在 ContentControl 上注册的一个区域,一次只有一个活动视图。设置和导航工作正常。现在我观察到的是,当我更改此 MainRegion 上的视图时,我对视图模型的所有绑定都会再次评估。
为了检查这一点,我在我的视图模型上添加了一个计数器来查看它的加载频率。当我更改视图 A -> 视图 B -> 视图 A 时,计数器将为 3:
- 正在进入视图 A
- 离开视图 A
- 正在进入视图 A
我正在使用正常调用来激活区域:
region.Activate(view);
在调试这个问题时,我看到当激活一个区域时,旧的区域被停用,最终设置
ContentControl.Content = null;
这似乎修改了可视化树并重新评估旧视图上的所有绑定。
这似乎是 MEF 和 WPF 问题的混合体。有什么方法可以防止在激活新区域时对绑定进行评估,或者在 WPF 端防止在 ContentControl.Content 变为 null 时重新评估绑定?
我发现了一个类似的问题,但在这里没有答案:
这个问题似乎是 ContentControl 本身的问题,请参阅此 post 了解更多信息:http://blogs.microsoft.co.il/tomershamam/2009/09/11/wpf-performance-sweets-contentcontrolcontent-null/
为避免在区域中的视图之间切换时出现性能问题,您可以通过对该区域使用另一个控件来将视图保留在可视化树中。用修改后的 ItemsControl
替换 ContentControl
。我在 post: https://vslepakov.blogspot.de/2014/09/navigate-faster-with-prism-and-wpf.html 中找到了解决方案。它适用于隐藏旧视图并显示新视图。
我把这个例子修改成这样:
public class RegionItemsControl : ItemsControl
{
protected override bool IsItemItsOwnContainerOverride(object item)
{
return false;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
((ContentPresenter)element).ContentTemplate = ItemTemplate;
}
}
将其添加到您的 shell 并将其标记为地区:
<controls:RegionItemsControl
prism:RegionManager.RegionName="MainRegion">
<controls:RegionItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</controls:RegionItemsControl.ItemsPanel>
<controls:RegionItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}"/>
</DataTemplate>
</controls:RegionItemsControl.ItemTemplate>
</controls:RegionItemsControl>
导航由事件处理,触发以下代码:
private FrameworkElement _lastView = null;
private bool LoadAndActivateWorkspaceAreaView(Type requestedViewType, IRegion region)
{
var viewToActivate = region.Views.FirstOrDefault(viewItem => viewItem.GetType() == requestedViewType) as FrameworkElement;
if (viewToActivate == null)
{
viewToActivate = MefContainer.GetExportedValue(requestedViewType) as FrameworkElement;
if (viewToActivate == null)
throw new InvalidOperationException("view not found!");
viewToActivate.Visibility = Visibility.Collapsed;
region.Add(viewToActivate); // Adds new view to RegionItemsControl
}
if (_lastView != null)
_lastView.Visibility = Visibility.Collapsed;
_lastView = viewToActivate;
_lastView.Visibility = Visibility.Visible;
}
此解决方案的一个问题是,存储在 RegionItemsControl
中的 "old" 视图的绑定会在向该区域添加新视图时重新评估一次。这似乎是我认为ItemsControl
的问题。
我在 MEF 应用程序中遇到了一个有趣的情况。主工作区是在 ContentControl 上注册的一个区域,一次只有一个活动视图。设置和导航工作正常。现在我观察到的是,当我更改此 MainRegion 上的视图时,我对视图模型的所有绑定都会再次评估。
为了检查这一点,我在我的视图模型上添加了一个计数器来查看它的加载频率。当我更改视图 A -> 视图 B -> 视图 A 时,计数器将为 3:
- 正在进入视图 A
- 离开视图 A
- 正在进入视图 A
我正在使用正常调用来激活区域:
region.Activate(view);
在调试这个问题时,我看到当激活一个区域时,旧的区域被停用,最终设置
ContentControl.Content = null;
这似乎修改了可视化树并重新评估旧视图上的所有绑定。
这似乎是 MEF 和 WPF 问题的混合体。有什么方法可以防止在激活新区域时对绑定进行评估,或者在 WPF 端防止在 ContentControl.Content 变为 null 时重新评估绑定?
我发现了一个类似的问题,但在这里没有答案:
这个问题似乎是 ContentControl 本身的问题,请参阅此 post 了解更多信息:http://blogs.microsoft.co.il/tomershamam/2009/09/11/wpf-performance-sweets-contentcontrolcontent-null/
为避免在区域中的视图之间切换时出现性能问题,您可以通过对该区域使用另一个控件来将视图保留在可视化树中。用修改后的 ItemsControl
替换 ContentControl
。我在 post: https://vslepakov.blogspot.de/2014/09/navigate-faster-with-prism-and-wpf.html 中找到了解决方案。它适用于隐藏旧视图并显示新视图。
我把这个例子修改成这样:
public class RegionItemsControl : ItemsControl
{
protected override bool IsItemItsOwnContainerOverride(object item)
{
return false;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
((ContentPresenter)element).ContentTemplate = ItemTemplate;
}
}
将其添加到您的 shell 并将其标记为地区:
<controls:RegionItemsControl
prism:RegionManager.RegionName="MainRegion">
<controls:RegionItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</controls:RegionItemsControl.ItemsPanel>
<controls:RegionItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}"/>
</DataTemplate>
</controls:RegionItemsControl.ItemTemplate>
</controls:RegionItemsControl>
导航由事件处理,触发以下代码:
private FrameworkElement _lastView = null;
private bool LoadAndActivateWorkspaceAreaView(Type requestedViewType, IRegion region)
{
var viewToActivate = region.Views.FirstOrDefault(viewItem => viewItem.GetType() == requestedViewType) as FrameworkElement;
if (viewToActivate == null)
{
viewToActivate = MefContainer.GetExportedValue(requestedViewType) as FrameworkElement;
if (viewToActivate == null)
throw new InvalidOperationException("view not found!");
viewToActivate.Visibility = Visibility.Collapsed;
region.Add(viewToActivate); // Adds new view to RegionItemsControl
}
if (_lastView != null)
_lastView.Visibility = Visibility.Collapsed;
_lastView = viewToActivate;
_lastView.Visibility = Visibility.Visible;
}
此解决方案的一个问题是,存储在 RegionItemsControl
中的 "old" 视图的绑定会在向该区域添加新视图时重新评估一次。这似乎是我认为ItemsControl
的问题。