Я работаю с комбинированным списком, чтобы показать список элементов с флажком. Проблема, с которой я столкнулся, заключается в том, что производительность при отображении (рендеринге, я думаю) списка элементов при открытии списка со списком замедляется при увеличении количества элементов (например, 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();
Я провел некоторое исследование и подумал, что это может быть связано с виртуализацией элементов, но я включил теги в список шаблонов стилей и в само поле со списком и не заметил никаких изменений.
Могу я еще что-нибудь проверить? Любая идея будет принята с благодарностью.
Кстати, он работает так же быстро в комбинированном списке из 10 000 элементов.
Мне нужно поле со списком, чтобы использовать элементы с флажком. Остальная часть настройки абсолютно необязательна. Как я мог изменить шаблон, чтобы сохранить только настройку элементов?
Я не предлагаю вам отказываться от своих настроек. Я предлагаю вам самостоятельно устранить неполадки, чтобы вы могли сузить круг вопросов и задать достаточно конкретный вопрос. Просто определите <ComboBox.ItemTemplate>.
Большое спасибо за ваше предложение. Фактически, окончательное решение, которое я принял, заключалось в том, чтобы просто использовать ItemTemplate в поле со списком. См. Ответ ниже.
Пожалуйста, но ...: O) 1) Не дай бог бизнес-логике в вашей модели представления нужно выбранное значение в вашем поле со списком ... потому что теперь вы устанавливаете его равным нулю ... 2) Не говоря уже о сомнительный UX, оставляющий пользователя в неведении относительно того, что или если что-то было выбрано. 3) даже если действительно необходимо скрыть эту информацию от пользователя, что является натяжкой, все равно это не то, как вы это делаете ...
Кстати, вы никогда не упоминали о скрытии выбранного значения в своем исходном вопросе ... вы просто добавили это в свой "отвечать" ниже из ниоткуда ...





В конце дня я избавился от 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» в поле со списком, когда оно закрыто, но что-то внутри этого кода ухудшало производительность.
нет заметной задержки находится в поле со списком 1000 элементов, используя стандартную, четкую, учебную привязку MVVM. А также с использованием стиля поля со списком по умолчанию. Итак, я предлагаю вам сделать то же самое, прежде чем вы начнете что-либо настраивать. Ваша привязка, кажется, требует немало изгибов и поворотов, прежде чем вызывать этот
ToList()в конце, что, скорее всего, даже не должно быть необходимо.