How to visualize usercontrols separately

I have a UserControl that draws a datacontext with Itemscontrol, etc. I have three objects of the same usercontrol, but with different datacontexts that are initialized when the program starts. The problem is that the datacontext is so large that it draws about 2000 UIelements on each of the objects. This takes a lot of time, and it really annoys me that WPF runs on the same UIThread, so my computer uses 1/8 of the total CPU power to draw it. How to do it faster?

Code (DynamicShelViewModel is a usercontrol)

dataContextBestSellers = new DynamicShelfViewModel(_config, dataRepository, ProductSelectionMode.BestSellers); dataContextNormal = new DynamicShelfViewModel(_config, dataRepository, ProductSelectionMode.Normal); dataContextFull = new DynamicShelfViewModel(_config, dataRepository, ProductSelectionMode.AllProducts); ScrollGrid = new Grid(); ScrollGrid.Children.Add(dataContextBestSellers); ScrollGrid.Children.Add(dataContextNormal); ScrollGrid.Children.Add(dataContextFull); 

It takes about 2 minutes.

This is the XAML code of DynamicShelfViewModel

 <Grid> <ItemsControl x:Name="ShelvesControl" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" DataContext="{Binding}" Width="{Binding Size.Width}" VerticalAlignment="Top" Height="{Binding Size.Height}" Grid.Column="0" Grid.Row="1" ItemsSource="{Binding ShelvesInViewPort}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel VerticalAlignment="Stretch " HorizontalAlignment="Stretch" Orientation="Vertical" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Grid Name="ShelfGrid" Height="{Binding Height}" MaxHeight="{Binding Height}" DataContext="{Binding}"> <Grid.Background> <SolidColorBrush Color="{Binding Color}" /> </Grid.Background> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="{Binding SplitterSize}" /> </Grid.RowDefinitions> <TextBlock Name="stretchingLabel" Height="{Binding SplitterSize}" Padding="0" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> <TextBlock.Background> <ImageBrush ImageSource="{Binding Converter={Utilities1:FancySourceConverter}, ConverterParameter=Images/ShelvesImages/shelfhorisontal.png}" /> </TextBlock.Background> <Grid VerticalAlignment="Stretch" Width="{Binding ElementName=stretchingLabel,Path=ActualWidth}" Height="{Binding ElementName=stretchingLabel,Path=ActualHeight}" HorizontalAlignment="Stretch"> <Grid.RowDefinitions> <RowDefinition Height="0.24*" /> <RowDefinition Height="0.62*" /> <RowDefinition Height="0.24*" /> </Grid.RowDefinitions> <my:CategoryLine VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" DataContext="{Binding ElementName=ShelfGrid, Path=DataContext}"> </my:CategoryLine> </Grid> </TextBlock> <TextBlock Name="stretchedLabel" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="0" Padding="0"> <ItemsControl ItemsSource="{Binding Products}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid DataContext="{Binding}" Width="{Binding ElementName=stretchedLabel, Path=ActualWidth}" MaxHeight="{Binding ElementName=stretchedLabel, Path=ActualHeight}" Height="{Binding ElementName=stretchedLabel, Path=ActualHeight}" Columns="{Binding Path=DataContext.Slots, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}" Rows="1" VerticalAlignment="Stretch" Name="ParentUniformGrid" HorizontalAlignment="Stretch" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <ItemsControl> <Grid Height="{Binding ElementName=stretchedLabel, Path=ActualHeight}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="{Binding ElementName=ParentUniformGrid,Path=DataContext.SplitterSize}" /> </Grid.RowDefinitions> <Image VerticalAlignment="Bottom" Grid.Row="0" HorizontalAlignment="Center" x:Name="ProductImage" Source="{Binding Converter={Utilities:ProductImageConverter}}" Height="{Binding ImageHeight}" MaxHeight="{Binding ImageHeight}" MouseLeftButtonUp="BuyProductUsingImage" /> <Label Padding="0" Margin="0 1 0 0" Grid.Row="1" Background="LightGray" VerticalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" HorizontalAlignment="Stretch"> <Label VerticalAlignment="Center" Margin="1" HorizontalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Background="#fff" Padding="0" MaxWidth="{Binding ElementName=ShelvesControl, Path=DataContext.PriceLabelWidthSize}" Width="{Binding ElementName=ShelvesControl, Path=DataContext.PriceLabelWidthSize}"> <Viewbox VerticalAlignment="Center" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="1" Background="#fff" HorizontalAlignment="Left"> <Label Background="Yellow" Padding="2 0 2 0" VerticalContentAlignment="Bottom" FontWeight="Bold" Content="{Binding Price}"> </Label> </StackPanel> </Viewbox> </Label> </Label> </Grid> </ItemsControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </TextBlock> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </UserControl> 
+4
source share
4 answers

There's more to Virtualizing ItemsControl than just setting VirtualizingStackPanel.IsVirtualizing . See this question for more details.

Mostly ItemsControl.Template requires a ScrollViewer to enable virtualization. I suspect that after you get the proper virtualization of the ItemsControl , you will see a dramatic increase in performance.

Virtualization means that only visible elements are rendered. When you scroll, the UI containers are reused and only the DataContext behind them changes. This means that instead of drawing 2,000 entries, you will only draw about 20 (or whatever you see)

0
source

Doing the same without a ViewBox and bindings to ActualWidth and ActualHeight will help a lot if it is possible to replace a lighter alternative.

0
source

As far as I know, there is only one way to get more UIThreads:

Each window can have its own UIThread (for example).

http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/

 private void OnCreateNewWindow(object sender, RoutedEventArgs e) { Thread thread = new Thread(() => { Window1 w = new Window1(); w.Show(); w.Closed += (sender2, e2) => w.Dispatcher.InvokeShutdown(); System.Windows.Threading.Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); } 

I don’t know if this would be a solution for you, but you asked for more UIThreads;)

0
source

Source: https://habr.com/ru/post/1380360/


All Articles