Slow User Control Loading WPF: ListBox doesn't virtualize - c#

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.

Related

Windows Phone ItemsControl drag and drop items

How to do drag and drop with elements in ItemsControl?
I turn AllowDrop and CanDrag in true but nothing works.
<ItemsControl Visibility="Collapsed" ItemsSource="{Binding MyItems}" Margin="0,3,0,0" Padding="5,0,0,0" CanDrag="True" AllowDrop="True">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="3" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border CanDrag="True" AllowDrop="True" Background="{Binding Color}" Height="{Binding Height}" Width="{Binding Width}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This does not work on the phone. I know about listView and GridView. I do not need Reorder Mode. I need a table where you can drag and drop items, and replace each other. 1 > 5 and 5 > 1 places. Swap elements of the first to the fifth, and the fifth on the first!
I have thought of doing something like CanvasTabelView. I do not know whether it is real!

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>

UniformGrid reduce spacing between rows in WPF

I am using a WPF UniformGrid to bind alist of items and the xaml is like this
<ListBox Name="lviewSearch" ItemsSource="{Binding SearchSettingsCollection}" SelectionMode="Multiple">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl Margin="3" Padding="5">
<DockPanel>
<Label Content="{Binding Label}" HorizontalAlignment="Stretch" Cursor="Hand" />
</DockPanel>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But if the no of items is less then the spacing between rows is too much like this
http://i.stack.imgur.com/Xr5qy.png
How can i ireduce thi s?
Like people said, your UniformGrid has too much vertical space so it expands the rows to take up all that space (stretches).
What you need to do is prevent this default behavior of stretching by setting
VerticalAlignment="Top"
The whole point of the UniformGrid is that the size of cells is uniform and therefore the same size. If you only have a small number of rows compared to the vertical space then each row is going to be pretty tall. Conversely if you have many rows and little vertical space then each row becomes tiny. If this is not an appropriate appearance then you need to use a different method of laying out.
Without knowing much more about the visual design it becomes impossible to recommend a possible alternative. Is the ListBox always the same size or will it vary in height? Does the number of displayed results vary or stay constant? All these change how you might achieve the required result.
One simple solution is to use grid outside Listbox. Set row height as auto. Now Uniform grid will take minimum space as required.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Name="lviewSearch" ItemsSource="{Binding SearchSettingsCollection}" SelectionMode="Multiple">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl Margin="3" Padding="5">
<DockPanel>
<Label Content="{Binding Label}" HorizontalAlignment="Stretch" Cursor="Hand" />
</DockPanel>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

Xaml code explanation

I am working on c# xaml using silverlight and i am bit confused about the hierarchy of this xaml code:
<UserControl.Resources>
<this:MyValueConverter x:Key="TabConverter"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" Canvas.Left="{Binding TabList, Mode=TwoWay, Converter={StaticResource TabConverter}}" Canvas.Top="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When i run it gives a big green color window(sorry if technical names are not correct), whereas it should also show red color somewhere in same window as it has Border Width="150" Background="red" .Could some one please explain me what this code is doing ?
ItemsControl really just binds to a list and applies a datatemplate (border with background red) for each item in the list. As for the reason you're only seeing green, well there's probably nothing in the TabList property on your viewmodel. That way, nothing in the items template renders, and all you see is green.
You'll need to make sure that TabList is bound correctly (it exists on your datacontext, whether that's a view model or not) and that it has items in it.
Here's a simpler version of what you may want to accomplish:
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

WPF ItemsControl layout issue

I have the following XAML which produces a vertical output of several TextBlocks and ListBoxes, however I want to change it so that it will go horizontally.
<StackPanel>
<TextBlock Margin="5" Text="Collated Results" FontWeight="Bold"
VerticalAlignment="Center" DockPanel.Dock="Top"/>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto" CanContentScroll="True">
<ItemsControl x:Name="lstCollatedSensorData">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" Width="100" Text="{Binding Name}"/>
<ListBox Margin="5" Width="100"
ItemsSource="{Binding CollatedResults}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
The Textbox and Listbox in the StackPanel show correctly individually, however, each iteration is placed on top of each other, where I want them to be placed side by side horizontally. I have tried inserting WrapPanels in various locations without success, so there is obviously something that I am missing. It almost seems like the ScrollViewer is forcing the ItemsControl to be vertical rather than horizontal.
Put a stackpanel with orientation horizontal in the ItemsControl's ItemsPanel
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Try setting Orientation on the stackpanel like so
StackPanel Orientation="Horizontal"

Categories