TabControl变得非常落后 [英] TabControl becoming very laggy

查看:102
本文介绍了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
            });
        }
    }
    

解决方案

我不确定您所拥有的复杂方案是什么,但是对于已发布的示例,问题不在tabControl中,而是在ItemsControl .

默认情况下,ItemsControl不支持UI虚拟化,您必须对其进行UI虚拟化,即,每当加载TabItem时,将创建用于承载项目的所有UI容器,即将创建1000个项目. >

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


替换

var itemsControl = new ItemsControl();

使用

var itemsControl = new ListBox();

您会发现性能有所不同.

如果要通过ItemsControl获得某些性能,则必须将其UI虚拟化.请参考答案此处以使其UI虚拟化.


更新

发表评论:

问题在于,随着您的使用,应用程序变得越来越慢 选择不同的标签.这是出乎意料的.由于每个项目都是 在加载新项目之前已卸载,并且由于每个项目都具有 相同的内容,我希望响应速度保持不变.

是的,没错,Unloaded事件被调用以获取最后选择的选项卡项目的内容,但是它仅使ItemsControl与Visual Tree断开连接.但是,其容器保持完整并保留在内存中.因此,每次切换都会在内存中创建新容器.我认为这是您的应用程序呆滞的合理原因.

您可以通过钩住StatusChanged事件来进行验证:

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

您会看到,每次切换到新的tabItem时都会调用它两次,但是切换到已访问过的tabItem时不会被调用.

We're using a Tabcontrol to display a number of items with rather expensive content, and the issue we're having is that as you iterate over the tabs (selecting them one by one), the responsiveness of the application becomes slower and slower.

This behavior is unexpected as from what I understand, as the selected tab changes, the previously selected tabs content is unloaded first, so that you're only paying the price for one tabs content at a time.

I've managed to simulate the behaviour with the code below. To reproduce :

  • Run the application
  • Launch the selected tabs contextmenu (the tabs header contextmenu), it will be responsive
  • From left to right, go through each tab, selecting one by one
  • By the time you reach tab ~10, the responsiveness of its contextmenu is now very laggy, as you click a checkbox, its animation takes a few seconds to run through

    <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
            });
        }
    }
    

解决方案

I am not sure about your complex scenario what you have but for posted sample, issue is not in tabControl but instead in ItemsControl.

ItemsControl by default does not support UI virtualization, you have to make it UI virtualized i.e. whenever TabItem gets loaded, all UI containers to host items will be created i.e. 1000 items will be created.

You can verify that by replacing ItemsControl with ListBox and you can see considerable increase in performance because ListBox by default support UI virtualization and only containers for visible items will be created (may be 100 at a time).


Replace

var itemsControl = new ItemsControl();

with

var itemsControl = new ListBox();

and you will see difference in performance.

In case you want some performance with ItemsControl, you have to make it UI virtualized. Refer to the answer here to make it UI virtualized.


UPDATE

For comment:

The problem is that the application becomes slower and slower as you select different tabs. This is unexpected. Due to each item being unloaded before loading a new item and due to each item having the same content, I'd expect the responsiveness to remain constant.

Yeah you are right that Unloaded event gets called for content of last selected tab item but it only disconnect ItemsControl from Visual Tree. However its containers remains intact and remains in memory. So, with every switch new containers are getting created in memory. That I guess is fair reason for sluggishness of your application.

That you can verify by hooking onto StatusChanged event:

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

You will see that it gets called twice on every switch to new tabItem but doesn't gets called on switch to already visited tabItem.

这篇关于TabControl变得非常落后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆