C# 组合框样式导致下拉速度非常慢

C# 组合框样式导致下拉速度非常慢,c#,wpf,xaml,combobox,C#,Wpf,Xaml,Combobox,我的ItemsSource combobox中有大约800个项目,当我第一次打开combobox时,需要很长时间(1-3秒)才能显示弹出窗口,就好像它生成了要显示的内容一样。但是,如果我禁用combobox的样式,它几乎会立即显示,不会出现任何减速。我已经尝试了所有我在网上读到的东西(到处都是虚拟化的ZingStack面板,禁用手写笔支持,触摸支持等等),但我不知道是什么导致了这种减速。下面是我的XAML代码: <Style x:Key="FocusVisual"> <Se

我的ItemsSource combobox中有大约800个项目,当我第一次打开combobox时,需要很长时间(1-3秒)才能显示弹出窗口,就好像它生成了要显示的内容一样。但是,如果我禁用combobox的样式,它几乎会立即显示,不会出现任何减速。我已经尝试了所有我在网上读到的东西(到处都是虚拟化的ZingStack面板,禁用手写笔支持,触摸支持等等),但我不知道是什么导致了这种减速。下面是我的XAML代码:

<Style x:Key="FocusVisual">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle StrokeDashArray="1 2" StrokeThickness="1" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" Margin="2"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<Style x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
  <Setter Property="OverridesDefaultStyle" Value="true"/>
  <Setter Property="IsTabStop" Value="false"/>
  <Setter Property="Focusable" Value="false"/>
  <Setter Property="ClickMode" Value="Press"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ToggleButton}">
        <Border x:Name="templateRoot" SnapsToDevicePixels="true" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="#e0e0e0">
          <Border x:Name="splitBorder" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" SnapsToDevicePixels="true" Margin="0" HorizontalAlignment="Right" BorderThickness="1" BorderBrush="Transparent">
            <Path x:Name="arrow" VerticalAlignment="Center" Margin="0" HorizontalAlignment="Center" Fill="Black" Data="F1 M 0,0 L 2.667,2.66665 L 5.3334,0 L 5.3334,-1.78168 L 2.6667,0.88501 L0,-1.78168 L0,0 Z"/>
          </Border></Border>
          <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
              <Setter Property="Fill" TargetName="arrow" Value="#3498db">
            </Setter>
          </Trigger>
            <Trigger Property="IsPressed" Value="True">
              <Setter Property="BorderBrush" TargetName="templateRoot" Value="#3498db">
            </Setter>
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
    <ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
      <Grid x:Name="templateRoot" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*" />
          <ColumnDefinition
                        MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0" />
        </Grid.ColumnDefinitions>
        <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling">
          <Popup x:Name="PART_Popup" AllowsTransparency="false" Grid.ColumnSpan="2"
                       IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                       Margin="1" MaxHeight="160" MinHeight="0" Placement="Bottom" MinWidth="{TemplateBinding ActualWidth}" >
            <Border x:Name="dropDownBorder" BorderBrush="#e0e0e0" BorderThickness="1" Background="White">
              <ScrollViewer x:Name="DropDownScrollViewer" >
                <Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
                  <Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top"
                                        Width="0">
                    <Rectangle x:Name="opaqueRect"
                                               Fill="{Binding Background, ElementName=dropDownBorder}"
                                               Height="{Binding ActualHeight, ElementName=dropDownBorder}"
                                               Width="{Binding ActualWidth, ElementName=dropDownBorder}" />
                  </Canvas>
                  <VirtualizingStackPanel  IsItemsHost="True" Orientation="Vertical" VirtualizationMode="Recycling" IsVirtualizing="True" x:Name="ItemsPresenter"

                                                KeyboardNavigation.DirectionalNavigation="Contained"
                                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                </VirtualizingStackPanel>
              </Grid>
            </ScrollViewer>
          </Border>
        </Popup>
      </VirtualizingStackPanel>
        <ToggleButton x:Name="toggleButton" BorderBrush="{TemplateBinding BorderBrush}"
                              BorderThickness="{TemplateBinding BorderThickness}"
                              Background="{TemplateBinding Background}" Grid.ColumnSpan="2"
                              IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                              Style="{StaticResource ComboBoxToggleButton}" />
        <ContentPresenter x:Name="contentPresenter"
                                  ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                                  ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                                  Content="{TemplateBinding SelectionBoxItem}"
                                  ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  IsHitTestVisible="false" Margin="{TemplateBinding Padding}"
                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
      </Grid>
      <ControlTemplate.Triggers>
        <Trigger Property="HasItems" Value="false">
          <Setter Property="Height" TargetName="dropDownBorder" Value="95"/>
        </Trigger>
      </ControlTemplate.Triggers>
    </ControlTemplate>
  </Style>
  <Style TargetType="{x:Type ComboBox}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderBrush" Value="#e0e0e0"/>
    <Setter Property="Foreground" Value="Black"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="None"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="OverridesDefaultStyle" Value="True">
  </Setter>
    <Setter Property="Template" Value="{StaticResource ComboBoxTemplate}"/>
  </Style>
  <Style TargetType="{x:Type ComboBoxItem}">
    <Setter Property="OverridesDefaultStyle" Value="True">
  </Setter>
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="Width" Value="Auto">
  </Setter>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="ComboBoxItem">
          <Border
                            Name="Border"
                            Padding="2"
                            SnapsToDevicePixels="true">
            <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling">
              <ContentPresenter />
            </VirtualizingStackPanel>
          </Border>
          <ControlTemplate.Triggers>
            <Trigger Property="IsHighlighted" Value="true">
              <Setter TargetName="Border" Property="Background"
                                        Value="#f0f0f0" />
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
              <Setter Property="Foreground" Value="Gray" />
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

下面是我如何将其添加到我的表单中

<ComboBox x:Name="GameCombobox"  Margin="20,0,18,0" Height="25" ItemsSource="{Binding Games, Mode=OneWay, Source={x:Static ui:Ui.Instance}}" SelectedValue="Name" IsEditable="False">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <VirtualizingStackPanel Orientation="Vertical" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" Height="45" Width="Auto">
                <Label FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="Black"   Content="{Binding Name}"/>
                <VirtualizingStackPanel Orientation="Horizontal" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Margin="0 -5 0 0" >
                    <Path Margin="5 5 0 0" Fill="Crimson"  Data="M 25 12 C 11.667228 12 1.25 24.34375 1.25 24.34375 A 1.0001 1.0001 0 0 0 1.25 25.65625 C 1.25 25.65625 11.667228 38 25 38 C 38.332772 38 48.75 25.65625 48.75 25.65625 A 1.0001 1.0001 0 0 0 48.75 24.34375 C 48.75 24.34375 38.332772 12 25 12 z M 25 14 C 27.627272 14 30.141915 14.544587 32.46875 15.375 C 34.032931 17.140338 35 19.450427 35 22 C 35 27.535732 30.535732 32 25 32 C 19.464268 32 15 27.535732 15 22 C 15 19.45074 15.935707 17.139242 17.5 15.375 C 19.834652 14.538846 22.362198 14 25 14 z M 14.1875 16.84375 C 13.439134 18.407614 13 20.155051 13 22 C 13 28.616268 18.383732 34 25 34 C 31.616268 34 37 28.616268 37 22 C 37 20.163179 36.580282 18.404914 35.84375 16.84375 C 41.492764 19.714987 45.555865 23.87765 46.59375 25 C 44.969234 26.756721 35.970973 36 25 36 C 14.029027 36 5.0307657 26.756721 3.40625 25 C 4.4456392 23.876024 8.5256535 19.715345 14.1875 16.84375 z M 25 17 C 22.238576 17 20 19.238576 20 22 C 20 24.761424 22.238576 27 25 27 C 27.761424 27 30 24.761424 30 22 C 30 19.238576 27.761424 17 25 17 z">
                        <Path.RenderTransform>
                            <ScaleTransform ScaleY="0.3" ScaleX="0.3"/>
                        </Path.RenderTransform>
                    </Path>
                    <Label Margin="-30 0 0 0" FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="#959699"  Content="{Binding Players}"/>
                </VirtualizingStackPanel>
            </VirtualizingStackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling"></VirtualizingStackPanel>
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

减速是由于您的数据模板非常“沉重”
是组合框的
项目模板。即使虚拟化工作正常,您可能会发现这一繁重的
DataTemplate
会导致滚动速度变慢,因为每次实现和虚拟化项目时,所有这些UI对象都将被实例化和呈现,然后被处置。有两件事可以让它“更轻”(更少、更简单的视觉对象),但仍然具有相同的外观

  • DataTemplate
    中的
    virtualzingstackpanel
    完全没有必要。如果您想要虚拟化,您不需要将它们“放在任何地方”,而是将它们放在非常特定的地方:
    ItemsPanelTemplate
    用于您正在使用的
    ItemsControl
    (在本例中是一个
    组合框
  • 使用一个简单的
    TextBlock
    而不是
    标签
    (这也可以消除对负边距的需要)
  • 您定义的非常复杂的
    路径
    图形正在为组合框中的每个项目实例化并重新呈现。不要把它放在
    数据模板
    中,而是创建一个复杂的
    路径
    可视化画笔
    ,作为静态资源,并将其用作像
    矩形
    这样简单的填充。由于笔刷是“可自由释放”的,因此它们可以重复使用,
    路径
    将仅实例化并呈现一次。我的猜测是,这条
    路径可能是您看到的绝大多数性能低下的罪魁祸首(VisualStudio中的评测将准确地告诉您布局/渲染花费了这么长时间的内容)。只渲染一次而不是800次,应该会有很大帮助
  • 您的VisualBrush(定义为静态资源):

    
    
    然后是您的组合框:

    <ComboBox x:Name="GameCombobox" Margin="20,0,18,0" Height="25" ItemsSource="{Binding Games, Mode=OneWay, Source={x:Static ui:Ui.Instance}}" SelectedValue="Name" IsEditable="False">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="Black" Text="{Binding Name}"/>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle Fill="{StaticResource ComboBoxItemIconBrush}" Width="45" Height="45"/>
                        <TextBlock FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="#959699" Text="{Binding Players}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling"></VirtualizingStackPanel>
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>
    </ComboBox>
    
    
    

    您可能需要使用一些边距,以及VisualBrush的ViewBox和ViewPort的大小以及矩形的宽度/高度,以使其看起来和以前的模板完全相同。我手边没有XAML渲染器,无法准确地看到您想要的是什么。

    因此,我怀疑其中有很多东西。比如为什么所有嵌套的虚拟化面板看起来都非常非常冗余?或者画布内部的嵌套矩形(与其父面板画布的高度/宽度绑定)具有明确的高度/宽度=0,或者是什么使rendertransforms成为必需的?或者是负利润率之类的。基本上,它看起来像你是超级复杂的部分,需要多次测量/排列传递等。不是消极的,但如果我是你,我会重构出地狱般的东西。矩形画布是由VS插入的,不是由我插入的。如果组合框中有800多个项目,你需要重新考虑你的设计。从用户的角度考虑一下。。。您想滚动浏览800个项目吗?也许一个树状视图延迟加载将是一个更好的方法。您可以使组合看起来/表现得像一棵树,并在功能和视觉上获得更好的设计。。目前,所有800件物品都在加载中。
    <ComboBox x:Name="GameCombobox" Margin="20,0,18,0" Height="25" ItemsSource="{Binding Games, Mode=OneWay, Source={x:Static ui:Ui.Instance}}" SelectedValue="Name" IsEditable="False">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="Black" Text="{Binding Name}"/>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle Fill="{StaticResource ComboBoxItemIconBrush}" Width="45" Height="45"/>
                        <TextBlock FontFamily="Resources/Fonts/#Lato" FontSize="14px" Foreground="#959699" Text="{Binding Players}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling"></VirtualizingStackPanel>
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>
    </ComboBox>