I am developing a WPF appl using C#.
I am trying to get my head around the async threading and tasks etc.
Basically I have a usercontrol, that i add to a stackpanel in my page. There can be many iterations of this usercontrol added to the stackpanel.
i.txtItemDescription.Text = "Item description " + ii.ToString() + ". Put a description here";
i.txtItemTitle.Text = "Item title " + ii.ToString() + ". Put a title here";
MainStack.Children.Add(i);
This works fine. However, when i transfer this appl to my windows 8.1 tablet it slows the display of these usercontrols(UCs) down dramatically.
I have tried using virtulization which had no effect as the data access and generation of the UCs poses no performance impact. It is the physical drawing of the controls on the screen.
So my question is as follows:
Any thoughts on how to would be appreciated!
Regds
Paul
First, you cannot create UI elements on a different thread than the one they will ultimately be rendered on, so forget about that possibility.
If it is the physical drawing of the controls that is causing performance problems, then you are probably not using UI virtualization correctly. The whole point of UI virtualization is to only perform layout and rendering for those controls which are actually in view, which means letting some sort of items host (like an ItemsControl
) generate the corresponding UI elements as needed. Pre-populating the entire panel defeats the purpose, and a regular StackPanel
does not support virtualization anyway. I suggest the following:
Instead of using a StackPanel
directly, use an ItemsControl
with a VirtualizingStackPanel
in its ItemsPanelTemplate
.
Instead of adding the user controls manually, bind the ItemsSource
to the underlying list of items, and let the ItemsControl
generate containers for the items as they are brought into view.
Use an ItemTemplate
to define how the items are rendered, e.g., the template content should be your user control with the appropriate bindings.
You can experiment with enabling container recycling on the VirtualizingStackPanel
; depending on your use case, it may help or hurt performance.
Anyway, if you follow this advice, you should not need a progress indicator, as the UI elements for your items will be generated as they are are needed, i.e., as they are scrolled into view.
If you've never used virtualization with a plain old ItemsControl
before (the default style does not support it), you can use the style below as a starting point. Note that it supports scrolling, unlike the default ItemsControl
style.
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility"
Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll"
Value="True" />
<Setter Property="ScrollViewer.PanningMode"
Value="Both" />
<Setter Property="Stylus.IsFlicksEnabled"
Value="False" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="VirtualizingStackPanel.IsVirtualizing"
Value="True" />
<Setter Property="VirtualizingStackPanel.VirtualizationMode"
Value="Recycling" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border x:Name="OuterBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Padding}"
Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="False">
<Setter TargetName="OuterBorder"
Property="Background"
Value="{DynamicResource {x:Static apthemes:AssetResourceKeys.ListBackgroundDisabledBrushKey}}" />
</Trigger>
<Trigger Property="IsGrouping"
Value="True">
<Setter Property="ScrollViewer.CanContentScroll"
Value="False" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing"
Value="True">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>