TabControl清除非活动标签页上的控件。

3

我正在使用MVVM模式开发我的应用。MainWindow包括一个TabControl,其中的DataContext与ViewModel进行了映射:

<Window.Resources>
  <ResourceDictionary>
    <DataTemplate x:Key="templateMainTabControl">
      <ContentPresenter Content="{Binding Path=DisplayName}" />
    </DataTemplate>

    <local:ViewModel x:Key="VM" />
    <local:WorkspaceSelector x:Key="WorkspaceSelector" />
    <local:TabOneView x:Key="TabOneView" />
    <local:TabTableView x:Key="TabTableView" />

    <DataTemplate x:Key="TabOne">
      <local:TabOneView />
    </DataTemplate>

    <DataTemplate x:Key="TabTable">
      <local:TabTableView />
    </DataTemplate>

  </ResourceDictionary>
</Window.Resources>


<TabControl Grid.Row="0"
            DataContext="{StaticResource VM}"
            ItemsSource="{Binding Workspaces}"
            SelectedItem="{Binding SelectedWorkspace}"
            ItemTemplate="{StaticResource templateMainTabControl}"
            ContentTemplateSelector="{StaticResource WorkspaceSelector}" />

WorkspaceSelector看起来像:

public class WorkspaceSelector : DataTemplateSelector
{
  public override DataTemplate SelectTemplate( object item, DependencyObject container )
  {
    Window win = Application.Current.MainWindow;
    Workspace w = ( Workspace ) item;
    string key = w.DisplayName.Replace( " ", "" );
    if ( key != "TabOne" )
    {
      key = "TabTable";
    }
    return win.FindResource( key ) as DataTemplate;
  }
}

这样,TabOne 将返回 DataTemplateTabOne 和其他两个标签将返回 DataTemplate TabTable

如果我运行应用程序并点击每个选项卡两次(1、2、3、1、2、3),我得到的结果与预期不符:


创建 TabOne 视图
创建 TabTwo 视图
创建 TabOne 视图
创建 TabTwo 视图

也就是说,如果 TemplateSelector 返回一个不同的值,则现有选项卡的控件将被丢弃,并创建新选项卡的控件;如果 TemplateSelector 返回相同的值,则什么都不会发生。

这正是我不想要的!我希望 TabControl 保留所有选项卡上的控件,并且我希望能够在从 TabTwoTabThree 的情况下通过代码创建不同的控件。我可以不考虑后者。但是,我该如何告诉 TabControl 在未选择时不要丢弃每个选项卡的控件?

1个回答

5
这是TabControl的一个功能,也是默认行为。为了节省内存,TabControl会卸载其内容区域中的可视树,并用新创建的可视树替换它以供新标签使用。为了证明这一点,您可以监听每个模板控件上的Unload事件,并注意到每次切换选项卡时都会触发该事件。
有两个原因可能会导致您想要覆盖此行为:
1. 您认为这会带来显著的性能损失。
2. 您正在失去控件的状态,因为任何丢失的可视状态都没有被 ViewModel 支持。
对于第一个原因,您不必担心。CPU 时间通常比 RAM 更便宜,而默认行为倾向于资源等式的更便宜一侧。如果您仍然认为您真的不想要这种行为,您可以在这里看到覆盖它的示例: https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf.Example/Controls/NonReloadingTabControl.cs 但是,我认为这是未来可能出现性能问题的“异味”,您应该花时间解决它,而不是拖延解决它。
对于第二个原因,您有两个选择:
1. 确保您想要保留的每个属性(如IsSelected等)都由 ViewModel 支持并保留该状态。
2. 为每个选项卡创建一个持久的UserControl,而不是绑定到 ViewModel(在您的情况下是工作区)。在 WAF 的“Writer”示例中有一个例子:http://waf.codeplex.com/

谢谢Anderson - 这是原因之一(它感觉很昂贵)。我会随波逐流。 --Amaca - amaca
我需要解决问题 #1, 我们有一些数据表格,每次切换标签页时设置非常耗费资源。我该如何告诉TabControl单独维护每个标签页的内容而不将它们卸载? - DarkwingDuck
@DarkwingDuck:Telerik似乎发现了一个黑客攻击。关于内存使用情况我不清楚,可能因人而异。http://www.pluralsight-training.net/community/blogs/eburke/archive/2009/04/30/keeping-the-wpf-tab-control-from-destroying-its-children.aspx 我建议您查看其中一款出色的WPF性能工具,以确定您的性能是否在您认为的地方丢失。这是链接:http://msdn.microsoft.com/en-us/library/aa969767.aspx - Anderson Imes
@Anderson Imes - 您的Telerik链接已失效。 - dcp
@dcp 这里有一个GitHub上的替代方案:https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf.Example/Controls/NonReloadingTabControl.cs - Anderson Imes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接