已经使用虚拟化的 Silverlight 组合框性能改进
Silverlight combobox performance improvements already using virtualization
我正在使用组合框来显示带有复选框的项目列表。我面临的问题是打开组合框列表时显示(我猜是渲染)项目列表的性能在增加项目数量时变慢(例如 300 个项目大约需要 3 秒,我需要显示 1000 秒) .
代码如下所示:
MultiSelComboBoxStyle.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<Style x:Key="CheckBoxListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid x:Name="RootElement">
<!--<CheckBox ClickMode="Press" Content="{Binding Path=Name}" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />-->
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Text}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MSMMultiSelComboBoxStyle" TargetType="ComboBox">
<Setter Property="Padding" Value="6,2,25,2"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Once"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="ContentPresenterBorder">
<Grid>
<ToggleButton x:Name="DropDownToggle" HorizontalAlignment="Stretch" HorizontalContentAlignment="Right" Margin="0" VerticalAlignment="Stretch">
<Path x:Name="BtnArrow" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z " HorizontalAlignment="Right" Height="4" Margin="0,0,6,0" Stretch="Uniform" Width="8">
<Path.Fill>
<SolidColorBrush x:Name="BtnArrowColor" Color="#FF333333"/>
</Path.Fill>
</Path>
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock x:Name="tb" Text=" "/>
</ContentPresenter>
</Grid>
</Border>
<Rectangle x:Name="DisabledVisualElement" IsHitTestVisible="false" Opacity="0" RadiusY="3" RadiusX="3"/>
<Rectangle x:Name="FocusVisualElement" IsHitTestVisible="false" Margin="1" Opacity="0" RadiusY="2" RadiusX="2" StrokeThickness="1"/>
<Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" >
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>true</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
<Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Margin="1,3,0,0"/>
<Path Data="M 0,0 L2,0 L 8,6 L8,8" Margin="1,3,0,0"/>
</Grid>
</Border>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" HorizontalAlignment="Stretch" Height="Auto">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<!--<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFFEFEFE" Offset="1"/>
-->
</LinearGradientBrush>
</Border.Background>
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<!--<ItemsPresenter/>-->
<ListBox x:Name="lstBox" SelectionMode="Multiple" ItemsSource="{TemplateBinding ItemsSource}" ItemContainerStyle="{StaticResource CheckBoxListBoxItemStyle}" HorizontalAlignment="Stretch" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
DeskCombo.xaml
<UserControl x:Class="Apama.UI.Surveillance.Controls.DeskCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="28" d:DesignWidth="400">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MultiSelComboBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ComboBox x:Name="cbDesk" Grid.Row="0" Grid.Column="0" Style="{StaticResource MSMMultiSelComboBoxStyle}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</Grid>
</UserControl>
这就是我将项目绑定到组合框的方式:
List<Desk> desks = new List<Desk>();
desks.Add(new Desk() { DeskId = UIConstants.SELECT_ALL_TEXT, DeskName = UIConstants.SELECT_ALL_TEXT, DimDeskId = UIConstants.SELECT_ALL_ID });
desks.AddRange(data.Desks.Values);
_items = new StaticDataStore<Desk>(GetItemName, desks, AddAll);
ComboBoxItems = new ComboBoxDataItemCollection(desks.Select(dk => new ComboBoxDataItem(dk.DimDeskId) { Text = dk.DeskName }));
ComboBoxItems.Owner = this;
// Bind
cbDesk.ItemsSource = ComboBoxItems.ToList();
我做了一些研究,我认为这可能与项目的虚拟化有关,但我将标签包含在样式模板列表框和组合框本身中,但没有看到任何变化。
还有什么我可以检查的吗?任何想法将不胜感激。
一天结束时,我摆脱了 MultiSelComboBoxStyle.xaml 并以这种方式更改了 DeskCombo.xaml:
<UserControl x:Class="Apama.UI.Surveillance.Controls.DeskCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="28" d:DesignWidth="400">
<Grid x:Name="LayoutRoot">
<ComboBox x:Name="cbDesk" Grid.Row="0" Grid.Column="0" DropDownClosed="hideSelected">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Text}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</Grid>
我加入了 "hideSelected" 回调,因为我不希望下拉窗口在关闭时显示任何值。该回调就是这样做的:
private void hideSelected(object sender, EventArgs e)
{
cbDesk.SelectedItem = null;
}
由于我对样式的首选是保持网站的外观和感觉,所以我很好地摆脱了 MultiSelComboBoxStyle.xaml。该文件的大部分功能是包含复选框项目并在组合框中隐藏值 "selected" ,但该代码中的某些东西搞砸了性能。
我正在使用组合框来显示带有复选框的项目列表。我面临的问题是打开组合框列表时显示(我猜是渲染)项目列表的性能在增加项目数量时变慢(例如 300 个项目大约需要 3 秒,我需要显示 1000 秒) .
代码如下所示:
MultiSelComboBoxStyle.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<Style x:Key="CheckBoxListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid x:Name="RootElement">
<!--<CheckBox ClickMode="Press" Content="{Binding Path=Name}" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />-->
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Text}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MSMMultiSelComboBoxStyle" TargetType="ComboBox">
<Setter Property="Padding" Value="6,2,25,2"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Once"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="ContentPresenterBorder">
<Grid>
<ToggleButton x:Name="DropDownToggle" HorizontalAlignment="Stretch" HorizontalContentAlignment="Right" Margin="0" VerticalAlignment="Stretch">
<Path x:Name="BtnArrow" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z " HorizontalAlignment="Right" Height="4" Margin="0,0,6,0" Stretch="Uniform" Width="8">
<Path.Fill>
<SolidColorBrush x:Name="BtnArrowColor" Color="#FF333333"/>
</Path.Fill>
</Path>
</ToggleButton>
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock x:Name="tb" Text=" "/>
</ContentPresenter>
</Grid>
</Border>
<Rectangle x:Name="DisabledVisualElement" IsHitTestVisible="false" Opacity="0" RadiusY="3" RadiusX="3"/>
<Rectangle x:Name="FocusVisualElement" IsHitTestVisible="false" Margin="1" Opacity="0" RadiusY="2" RadiusX="2" StrokeThickness="1"/>
<Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" >
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>true</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
<Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Margin="1,3,0,0"/>
<Path Data="M 0,0 L2,0 L 8,6 L8,8" Margin="1,3,0,0"/>
</Grid>
</Border>
<Popup x:Name="Popup">
<Border x:Name="PopupBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" HorizontalAlignment="Stretch" Height="Auto">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<!--<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FFFEFEFE" Offset="1"/>
-->
</LinearGradientBrush>
</Border.Background>
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
<!--<ItemsPresenter/>-->
<ListBox x:Name="lstBox" SelectionMode="Multiple" ItemsSource="{TemplateBinding ItemsSource}" ItemContainerStyle="{StaticResource CheckBoxListBoxItemStyle}" HorizontalAlignment="Stretch" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
DeskCombo.xaml
<UserControl x:Class="Apama.UI.Surveillance.Controls.DeskCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="28" d:DesignWidth="400">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MultiSelComboBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ComboBox x:Name="cbDesk" Grid.Row="0" Grid.Column="0" Style="{StaticResource MSMMultiSelComboBoxStyle}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</Grid>
</UserControl>
这就是我将项目绑定到组合框的方式:
List<Desk> desks = new List<Desk>();
desks.Add(new Desk() { DeskId = UIConstants.SELECT_ALL_TEXT, DeskName = UIConstants.SELECT_ALL_TEXT, DimDeskId = UIConstants.SELECT_ALL_ID });
desks.AddRange(data.Desks.Values);
_items = new StaticDataStore<Desk>(GetItemName, desks, AddAll);
ComboBoxItems = new ComboBoxDataItemCollection(desks.Select(dk => new ComboBoxDataItem(dk.DimDeskId) { Text = dk.DeskName }));
ComboBoxItems.Owner = this;
// Bind
cbDesk.ItemsSource = ComboBoxItems.ToList();
我做了一些研究,我认为这可能与项目的虚拟化有关,但我将标签包含在样式模板列表框和组合框本身中,但没有看到任何变化。
还有什么我可以检查的吗?任何想法将不胜感激。
一天结束时,我摆脱了 MultiSelComboBoxStyle.xaml 并以这种方式更改了 DeskCombo.xaml:
<UserControl x:Class="Apama.UI.Surveillance.Controls.DeskCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="28" d:DesignWidth="400">
<Grid x:Name="LayoutRoot">
<ComboBox x:Name="cbDesk" Grid.Row="0" Grid.Column="0" DropDownClosed="hideSelected">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Text}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</Grid>
我加入了 "hideSelected" 回调,因为我不希望下拉窗口在关闭时显示任何值。该回调就是这样做的:
private void hideSelected(object sender, EventArgs e)
{
cbDesk.SelectedItem = null;
}
由于我对样式的首选是保持网站的外观和感觉,所以我很好地摆脱了 MultiSelComboBoxStyle.xaml。该文件的大部分功能是包含复选框项目并在组合框中隐藏值 "selected" ,但该代码中的某些东西搞砸了性能。