TabControl becoming very laggy

社会主义新天地 提交于 2021-02-11 12:48:58

问题


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

回答1:


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.



来源:https://stackoverflow.com/questions/22579798/tabcontrol-becoming-very-laggy

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!