Using a template for a custom control deriving from ListBox causes filtering of ItemSource to become slow. The filtering is done in the get of the ItemSource that the control is bound to. This problem is not present when a normal ListBox is used, so why should it be any different for a custom ListBox?
Filtering:
public IEnumerable<LibraryViewModel> Libraries {
get {
if (!string.IsNullOrEmpty(this.LibrarySearchString))
return _libraries.Where(lib => IsLibraryMatch(lib, this.LibrarySearchString));
else
return _libraries.OrderBy(lib => !lib.IsFavourite);
}
}
Using the control:
<con:FilterListBox Grid.Row="1"
ItemsSource="{Binding Libraries}"
SelectedItem="{Binding SelectedLibrary}"
ItemTemplate="{StaticResource
LibraryItemTemplate}"
SearchString="{Binding LibrarySearchString, Mode=TwoWay}"
IsSearching="False"
Margin="4"/>
The control template:
<Style x:Key="{x:Type con:FilterListBox}" TargetType="{x:Type con:FilterListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type con:FilterListBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<TextBlock Text="Search"
VerticalAlignment="Center"/>
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=SearchString,
UpdateSourceTrigger=PropertyChanged}"
Margin="4,0,0,0"/>
</DockPanel>
<ScrollViewer Grid.Row="1" CanContentScroll="True">
<StackPanel IsItemsHost="True"
HorizontalAlignment="Stretch"/>
</ScrollViewer>
<TextBlock Grid.Row="1"
Text="Searching..."
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsSearching,
Converter={StaticResource CollapsedIfFalseConverter}}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks for any help.
The slow behavior of your
FilterListBoxmay come with an Virtualization issue. You replaced the ItemsHost of theListBoxwith a simpleStackPanel. By default, the ListBox uses aVirtualizingStackPanel, which virtualizes the Items whenever possible. See the default ListBox Template as a reference. If you have a simple StackPanel as ItemsPresenter, the ListBox has to re-render every item when your filter changes. Depending on the number of items, this can cause your slow behavior. Try to use the default itemshost instead. You should also know, that virtualization is only possible with ‘simple’ items (same Height for every item basically).