我们正在使用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
});
}
}
答案 0 :(得分: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
事件被调用最后选择的标签项的内容,但它只从Visual Tree断开ItemsControl。然而,它的容器保持完整并留在记忆中。因此,每个开关都会在内存中创建新的容器。我认为这是你的申请迟缓的公平理由。
您可以通过挂钩StatusChanged
事件进行验证:
itemsControl.ItemContainerGenerator.StatusChanged += (s, e) => { };
您将看到每次切换到新tabItem时都会调用它两次,但在切换到已访问过的tabItem时不会调用它。