wpf 慢速组合框性能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11937268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Slow ComboBox Performance
提问by Sisi
As explained in the following article http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx, I use the VirtualizingStackPanelto improvethe performanceof my project's ComboBoxes.
如以下文章http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx 所述,我使用VirtualizingStackPanel来改进我的项目ComboBoxes的性能。
And it works great ... until I apply a style to ComboBox to change the layout (I found the style here : http://msdn.microsoft.com/en-us/library/ee230084.aspx)
它工作得很好......直到我将样式应用于 ComboBox 以更改布局(我在这里找到了样式:http: //msdn.microsoft.com/en-us/library/ee230084.aspx)
Here is the source code of a sample which demonstrate the matter (figuring that ItemSource propery of the ComboBox are filled with 10 000 items).
这是演示此问题的示例的源代码(计算 ComboBox 的 ItemSource 属性填充了 10 000 个项目)。
If anyone has an idea ...
如果有人有想法...
<Window.Resources>
<!-- Fill Brushes -->
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#BBB" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="0.1"/>
<GradientStop Color="#EEE" Offset="0.9"/>
<GradientStop Color="#FFF" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Black" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#E5E5E5" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<!-- Border Brushes -->
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="2" Background="{StaticResource NormalBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" CornerRadius="2,0,0,2" Margin="1" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Fill="{StaticResource GlyphBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter TargetName="Border2" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border2" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="ComboBoxBaseStyle" TargetType="ComboBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="2" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="3,3,23,3" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" Background="{StaticResource WindowBackgroundBrush}" BorderThickness="1" BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="CustomerComboBox_WithoutStyle" SelectedValuePath="Id" DisplayMemberPath="Text" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
<ComboBox x:Name="CustomerComboBox_WithStyle" SelectedValuePath="Id" DisplayMemberPath="Text" Style="{StaticResource ComboBoxBaseStyle}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</StackPanel>
回答by Joachim Kerschbaumer
The problem of your style is that it does not use any kind of UI Virtualization. Try replacing the StackPanel with a VirtualizingStackpanel and set the VirtualizationMode to Recycle and you will see a huge performance boost.
你的风格的问题是它没有使用任何类型的 UI 虚拟化。尝试将 StackPanel 替换为 VirtualizingStackpanel 并将 VirtualizationMode 设置为 Recycle,您将看到巨大的性能提升。
Your approach forces WPF to realize a container and FrameworkElement for each of your 10k items, which takes an eternity as you have only 1 UI thread. Just replace
您的方法强制 WPF 为您的 10k 个项目中的每一个实现一个容器和 FrameworkElement,这需要永恒,因为您只有 1 个 UI 线程。只需更换
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
with
和
<VirtualizingStackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
and see if it gets faster.
看看它是否变得更快。
To be more precise, you override the ItemsPanel in your derived styles, but have no "ItemsPresenter" in the base style. Instead to use the StackPanel "hardcoded"
更准确地说,您在派生样式中覆盖了 ItemsPanel,但在基本样式中没有“ItemsPresenter”。而是使用 StackPanel“硬编码”
回答by Michel Keijzers
So many items probably is the result of a (UI) design flaw.
如此多的项目可能是(UI)设计缺陷的结果。
Try using a listbox or multiple combo boxes where the first combo box is a category and second is a sub category of the first.
尝试使用列表框或多个组合框,其中第一个组合框是一个类别,第二个是第一个组合框的子类别。
回答by Clinton Ward
having 10000 items in a combox is not very good design. MaxDropDownItems might be able to help you as less rendering is required. (this is the number of visible items shown when clicking the dropdown)
在一个组合框中有 10000 个项目并不是很好的设计。MaxDropDownItems 可能会为您提供帮助,因为需要较少的渲染。(这是单击下拉菜单时显示的可见项目数)
But, you should consider using a listbox. When you apply a listbox you should uses pages and on each page have 1000 records. Or use a search box
但是,您应该考虑使用列表框。当您应用列表框时,您应该使用页面并且在每个页面上有 1000 条记录。或使用搜索框

