MEF:如何在离开视图时禁用绑定的重新评估

MEF: How can I disable reevaluation of bindings when leaving a view

我在 MEF 应用程序中遇到了一个有趣的情况。主工作区是在 ContentControl 上注册的一个区域,一次只有一个活动视图。设置和导航工作正常。现在我观察到的是,当我更改此 MainRegion 上的视图时,我对视图模型的所有绑定都会再次评估。

为了检查这一点,我在我的视图模型上添加了一个计数器来查看它的加载频率。当我更改视图 A -> 视图 B -> 视图 A 时,计数器将为 3:


我正在使用正常调用来激活区域:

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的问题。