How to filter ListBox items without needing to replace the whole ItemsSource collection? #15265
-
Hi, I'm a student and I'm curently learning Avalonia UI MVVM; from my last post I think I made some progress, but I came across a problem for which I cannot find a solution by myself. I have a ListBox that holds at first something like 570 objects ( with an item template ), and above the ListBox I have a set of buttons: when I click on one of them the items in the ListBox gets filtered based on some value. The problem is that the operation is extremely slow, I'm talking about 1.5 to 2 seconds of waiting when resetting the filter and all items need to be visualized. public string SearchString {
get => this._searchString;
set => this.RaiseAndSetIfChanged(ref this._searchString, value); }
public List<Spell> ItemSource
{
get => this._itemSource;
set => this.RaiseAndSetIfChanged(ref this._itemSource, value);
}
// Commands
FilterAsRitual = ReactiveCommand.Create(() =>
{
this.SearchString = "";
this._dataManager.UpdateRitualFilter();
this.ItemSource = this._dataManager.GetData();
});
FilterAsHomebrew = ReactiveCommand.Create(() =>
{
this.SearchString = "";
this._dataManager.UpdateHomebrewFilter();
this.ItemSource = this._dataManager.GetData();
});
FilterByLevel = ReactiveCommand.Create((string s) =>
{
this.SearchString = "";
this._dataManager.UpdateLevelFilterForLevel(int.Parse(s));
this.ItemSource = this._dataManager.GetData();
}); I'll provide a little explanation: _dataManager is a class I designed to execute queryes on the database that contains all the items; each time one of the button is pressed the filter connected to it gets updated, and then I get the data from the database that corresponds to the query with that filter ( and maybe others ) active. AXAML: <ListBox x:Name="SpellListBox"
Grid.Row="2"
Grid.ColumnSpan="3"
Background="Transparent"
SelectionMode="Multiple, Toggle"
SelectedItems="{Binding Items}"
ItemsSource="{Binding ItemSource}">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="3"/>
<Setter Property="CornerRadius" Value="5"/>
<Setter Property="MinWidth" Value="150"/>
<Setter Property="MinHeight" Value="50"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Height" Value="75"/>
</Style>
<Style Selector="ListBoxItem:selected">
<Setter Property="Background" Value="Black"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="5"
Background="{Binding, Converter={StaticResource SpellCastingTimeConv}}"
BorderBrush="Black"
BorderThickness="1"
Margin="0"
Padding="3" >
<DockPanel>
<DockPanel VerticalAlignment="Center"
DockPanel.Dock="Top" >
<TextBlock FontWeight="Bold"
Text="{Binding Name}"/>
<TextBlock HorizontalAlignment="Right"
Text="{Binding Level}"/>
</DockPanel>
<DockPanel>
<TextBlock VerticalAlignment="Bottom"
Text="{Binding CastTime}"/>
<Border Background="{Binding, Converter={StaticResource SpellTypeConv}}"
BorderThickness="1"
CornerRadius="5"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="50"
Padding="0, 0.2, 0, 0.1">
<TextBlock FontSize="10"
TextAlignment="Center"
Text="{Binding Type}"/>
</Border>
</DockPanel>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox> If I missed something or I need to clarify let me know, and I'll provide a better explanation as soon as possible. Every advice is welcome. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 13 replies
-
Use a virtualized panel, it will make things faster in general. Also if you are using Reactive UI it ships with some special collections that work pretty well for large amounts of data. Such as a SourceCache. |
Beta Was this translation helpful? Give feedback.
-
You can use this library, but to be honest I personally find it quite cumbersome to use. |
Beta Was this translation helpful? Give feedback.
I don't think there is a specific docs page for it. You are using a WrapPanel which is not virtualised. As such it will attempt to render/realise everything at once. A virtualised panel however will only attempt to render/realise what is visible on screen (plus some buffer on either side to allow for smooth scrolling). This results in:
Depending on what you are doing, a virtualised panel is the only way to get decent performance. EG trying to display >3k images in image gallery is nearly impossible on most hardware without it. But because only things you can see actually exists in the panel, it can result in some weird visual i…