【问题标题】:TabControl becoming very laggyTabControl 变得非常滞后
【发布时间】:2014-03-23 00:48:50
【问题描述】:

我们使用 Tabcontrol 来显示一些内容相当昂贵的项目,而我们遇到的问题是,当您遍历选项卡(一个一个地选择它们)时,应用程序的响应速度会变慢而且更慢。

据我了解,这种行为是出乎意料的,随着所选标签的更改,先前选择的标签内容首先被卸载,因此您一次只需为一个标签内容支付费用。

我已经设法用下面的代码模拟了这种行为。重现:

  • 运行应用程序
  • 启动选定的选项卡上下文菜单(选项卡标题上下文菜单),它将是响应式的
  • 从左到右,逐个选择标签页
  • 当你到达 tab ~10 时,它的上下文菜单的响应现在非常迟钝,当你点击一个复选框时,它的动画需要几秒钟才能运行完

    <Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <Style TargetType="{x:Type TabItem}"
               BasedOn="{StaticResource {x:Type TabItem}}">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu>
                        <CheckBox Content="CheckBox" />
                        <CheckBox Content="CheckBox" />
                        <CheckBox Content="CheckBox" />
                        <CheckBox Content="CheckBox" />
                        <CheckBox Content="CheckBox" />
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <TabControl Name="tabControl" />
    

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            for (int i = 0; i < 25; i++)
            {
                CreateTab();
            }
        }
    
        void CreateTab()
        {
            var itemsControl = new ItemsControl();
            for (int i = 0; i < 1000; ++i)
            {
                itemsControl.Items.Add(new TextBox());
            }
    
            tabControl.Items.Add(new TabItem()
            {
                Header = string.Format("Tab{0}", tabControl.Items.Count),
                Content = itemsControl
            });
        }
    }
    

【问题讨论】:

    标签: wpf tabcontrol lag


    【解决方案1】:

    我不确定您所拥有的复杂场景,但对于发布的示例,问题不在 tabControl 中,而是在 ItemsControl

    ItemsControl 默认不支持 UI 虚拟化,您必须使其 UI 虚拟化,即每当加载 TabItem 时,将创建所有用于托管项目的 UI 容器,即将创建 1000 个项目。

    您可以通过将ItemsControl 替换为ListBox 来验证这一点,并且您可以看到性能显着提高,因为默认情况下 ListBox 支持 UI 虚拟化,并且只会创建可见项目的容器(一次可能是 100 个)。


    替换

    var itemsControl = new ItemsControl();
    

    var itemsControl = new ListBox();
    

    您会看到性能上的差异。

    如果您想要使用 ItemsControl 获得一些性能,则必须将其 UI 虚拟化。参考答案here将其UI虚拟化。


    更新

    评论:

    问题是应用程序变得越来越慢 选择不同的选项卡。这是出乎意料的。由于每个项目都 在加载新项目之前卸载并且由于每个项目都有 相同的内容,我希望响应能力保持不变。

    是的,你是对的,Unloaded 事件被调用以获取最后选择的选项卡项的内容,但它只会断开 ItemsControl 与 Visual Tree 的连接。然而,它的容器保持完整并保留在内存中。因此,每次切换都会在内存中创建新容器。我想这是您的应用程序缓慢的合理原因。

    您可以通过挂钩StatusChanged 事件来验证:

    itemsControl.ItemContainerGenerator.StatusChanged += (s, e) => { };
    

    您会看到它在每次切换到新 tabItem 时被调用两次,但在切换到已访问的 tabItem 时不会被调用。

    【讨论】:

    • 我故意创建了这样的 itemsControl 来模拟具有“昂贵内容”的 TabItem。我想你误解了这个问题。问题是当您选择不同的选项卡时,应用程序变得越来越慢。这是出乎意料的。由于每个项目在加载新项目之前都被卸载并且由于每个项目具有相同的内容,我希望响应能力保持不变。
    • 内存中的项目似乎很奇怪,但与可视化树断开连接会影响性能。
    猜你喜欢
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 2012-02-22
    • 1970-01-01
    • 2014-03-19
    • 2013-06-12
    • 1970-01-01
    相关资源
    最近更新 更多