ListView vs ListBox performance - c#

So I have been dealing with a problem representing 10k+ rows in a listview (I might need pagination, but this is not about that), I had 2 problems:
Item source loading took at least 10 seconds to load into the listview which made my UI hang
Lag while focusing the listview
So I wanted to compare the same thing using a listbox than a datagrid. And I was amazed how the listbox reduced the loading time to almost nothing and also there is no lag.
Listview:
<ListView ItemsSource="{Binding SymbolContext}" BorderThickness="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ListBox:
<ListBox ItemsSource="{Binding SymbolContext}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So my question is why did it take for the listview so much to represent the data and why did the listbox perform so well?

Related

Slow User Control Loading WPF: ListBox doesn't virtualize

My MVVM WPF application uses Linq2SQL for using SQL Server Express. I noticed after populating the database with real data I get some big delays for the UI to update and thought is was my query/ grouping strategy. But, while some of the data fills take more than 100ms, rarely do they take more than 200ms but I'm seeing a lag of up to 3 seconds on the window refresh. EDIT FOR BREVITY:
I was wrapping my ItemsControl in a ScrollViewer:
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" ScrollChanged="ScrollViewer_ScrollChanged">
<ItemsControl x:Name="DivisionItems" ItemsSource="{Binding oObsByDiv}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<uc:ucObservationsHeader/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
But after some hints from below and reading up on Virtualization I now use a ListBox like so:
<ListBox x:Name="DivisionItems" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2"
ItemsSource="{Binding oObsByDiv}"
ScrollViewer.CanContentScroll="True"
VirtualizingStackPanel.ScrollUnit="Pixel">
<ListBox.Template>
<ControlTemplate>
<ScrollViewer VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<uc:ucObservationsHeader/>
</DataTemplate>
</ListBox.ItemTemplate>
The user control used for the Items in that template then calls another user control that I'm wrapping in another ListBox in a very similar manner:
<ListBox ItemsSource="{Binding lObs}" Grid.Row="1" Grid.Column="1"
HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True"
VirtualizingStackPanel.ScrollUnit="Pixel">
<ListBox.Template>
<ControlTemplate>
<ScrollViewer VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<uc:ucObservationsView/>
</DataTemplate>
</ListBox.ItemTemplate>
But the multiple second lag still exists. The outer user control is instantiated 15 times, and the inner one has on average 15 items each. What is it that is breaking virtualization in this case? I keep stripping out the ScrollUnit and CanContentScroll in one or both places, as well as the HorizontalContentAlignement and the HorizontalScrollBar visibility, but those just affect the look without seeming to be the cause for breaking virtualization.

Nested ItemsControls optimizations

I have a question regarding nested collections usage in UWP apps with XAML/C#.
Let's say I have a list of items with multiple images in each.
I need to show a scrollable list with all of the images inside the item data.
So far I can see a solution to create GridView with ItemsTemplate that has ItemsControl inside it. But it seams very slow and not optimized solution.
Is there any better suggestion to solve that?
Without much context, I can only think of following :
You have a large amount of data to be displayed, but not all at once. In this case you should consider using controls that support virtualization.
Flattening the data source before binding it. This may improve the performance by a little.
Update
Here is how you can do it :
<ListViewItem ItemsSource="{Binding Posts}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Message}" />
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Photos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListViewItem>

Unable to bind collection to ComboBox in silverlight

I've a ObservableCollection, when I want to display this ObservableCollection with CheckBox I am simply binding the contents to CheckBox but when I want to display the same collection by using ComboBox I am unable to do that. Any suggestions?
XAML: Display collection using CheckBox --WORKS
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<CheckBox Content="{Binding Display}" Margin="10,0,0,0" /> // Display is the collection.
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
XAML: Display collection using ComboBox --NOTHING OVER HERE
<ItemsControl ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in ComboBox.-->
Approach - 1
<ComboBox>
<ComboBoxItem Content="{Binding Display}"/>
</ComboBox>
Approach - 2
<ComboBox ItemsSource="{Binding Path=Synonyms}" DisplayMemberPath="Display"/>
Approach - 3
<ComboBox >
<ComboBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Green" BorderThickness="1" Padding="5">
<TextBlock Text="{Binding Path=Display,StringFormat='Display: {0}'}" />
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Output:
I want to display items(one,two,three, etc.) inside oneComboBox with Select All option. I've tried several approaches but nothing. What am I missing here?
The checkbox is not designed to hold multiple items unlike the Combobox so implementing a system designed for the checkbox is not relevant for the combobox.
To solve your issue, remove the combobox from the ItemsControl and have it stand on its own:
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
Which tells the combobox to bind its ItemsSource to the data context which is unspecified, which is fine, so it then gets it's parent's data context. That process works its way up to each parent until it finds a bound data context (most likely the page's datacontext to a VM instance).
Assuming that the data context is valid at some point in the visual tree, it will bind to that instance and look for a property named Synonyms. From the Synonyms property it will use that as a list to display items.
To show (display) text in the combobox (instead defaulting to the item's ToString()) the combobox will show the string from the item's property Display.
Giving a list of items in one drop down.
The short answer, is you should use a ComboBox as the root element, not ItemsControl. CompboBox is just a specialized version of ItemsControl.
<ComboBox ItemsSource="{Binding Synonyms}" DisplayMemberPath="Display"/>
The longer answer.
ComboBox derives from ItemsControl, so you get all the features the base class, plus additional features.
ItemsControl (and its derived classes) provides a way of repeating a set of data in the UI. The DataTemplate is where you specify what UI you want for each "row" of data in the Synonyms source.
What you are doing is asking Silverlight to create a separate ComboBox for each underlying data row.
You can still use a DataTemplate within the ComboBox. Like this.
<ComboBox ItemsSource="{Binding Synonyms}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Display items in CheckBox-->
<TextBox Text="{Binding Display}"
Margin="10,0,0,0"
FontWeight="Bold" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Windows 8 GridView groups width

I have problem with my gridview. I'm displaying grouped data in it and using VariableSizedWrapGrid for displaying items. The problem is that every group has the same width equal to the most item. Even if a group contains only 1 item it has width like it was 20 items there. How to make these ItemsPanels have variable width?
My issue is almost the same as described here but when I use VirtualizingStackPanel as GridView.ItemsPanel my VariableSizedWrapGrid is displayed in one row and I need it to be displayed in two rows.
<SemanticZoom.ZoomedInView>
<GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False"
ScrollViewer.IsVerticalScrollChainingEnabled="False"
ItemTemplate="{StaticResource PatientMediaFileBigItemTemplate}"
ItemsSource="{Binding Source={StaticResource PatientVisits} }"
IsItemClickEnabled="True"
SelectionMode="None"
Margin="0,0,0,0" ItemClick="MediaFileIcon_Click"
>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Button Content="{Binding DateOfVisit, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:dd MMM yyyy}'}" FontSize="28" Foreground="Black" BorderThickness="0" Click="ButtonVisit_OnClick"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0" Width="Auto" Background="BlueViolet"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
You might need to change the ItemsPanel of your GridView to a StackPanel, but note this will limit the number of items you can put in your GridView as it disables virtualization. A better option might be to keep showing a limited number of items in a group, but add a button (really the group header button with a chevron glyph should work) to navigate to a full view of the selected group.

Scroll ListBox in terms of logical units with horizontal orientation

In my application, I have the following ListBox:
<ListBox ItemsSource="{Binding Path=ItemsSource}" ScrollViewer.CanContentScroll="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Height="300">
<!-- One ProgressBar and multiple TextBlocks -->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This way, I have multiple items on the same line. If there are too many items for one line, the following items are sent to the next line.
The problem I am having is that ScrollViewer.CanContentScroll="True" has no effect on the ListBox. The scroll down is still processing in terms of physical units. When I comment the ListBox.ItemsPanel part of the XAML, the scroll down is working properly, but only one item is displayed on each line...
So my question is the following: How to combine the scroll down in terms of logical units with a horizontal orientation of the items?
Thanks!

Categories