我有一个UserControl使用Itemscontrol等绘制datacontext。我有三个相同usercontrol但具有不同datacontexts的对象,这些对象在程序启动时初始化。问题是datacontext非常大,所以它在每个对象上绘制了大约2000个UIelements。这需要花费很多时间,而真正令我讨厌的是WPF在单个UIThread中运行,因此我的计算机使用总CPU功率的1/8来绘制它。我怎样才能让它更快?
代码(DynamicShelViewModel是一个用户控件)
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);
这需要大约2分钟才能完成。
这是DynamicShelfViewModel的XAML代码
<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>
答案 0 :(得分:0)
对于DataGrid
,我发现了这篇文章:
http://wpf.codeplex.com/wikipage?title=SelectAll%28%29%20Performance&referringTitle=Tips%20%26%20Tricks&ProjectName=wpf
还有 http://wpf.codeplex.com/discussions/66291?ProjectName=wpf
也许它已经有所帮助。
答案 1 :(得分:0)
虚拟化ItemsControl
不仅仅是设置VirtualizingStackPanel.IsVirtualizing
。有关详细信息,请参阅this question
基本上,您的ItemsControl.Template
需要ScrollViewer
才能启用虚拟化。我怀疑,一旦你的ItemsControl
正确虚拟化,你就会看到性能的显着提升。
虚拟化意味着只渲染可见项。滚动时,UI容器会重新使用,只有它们后面的DataContext
会发生变化。这意味着不是绘制2000条记录,而是绘制大约20条(或者可见多条)
答案 2 :(得分:0)
如果没有ViewBox
并且绑定到ActualWidth
和ActualHeight
,那么做同样的事情会有很大的帮助,如果可以用更轻的替代品替换它。
答案 3 :(得分:0)
据我所知,只有一种方法可以获得更多UIThreads:
每个窗口都可以拥有自己的UIThread(例如)。
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();
}
不知道,如果这对你来说是一个解决方案,但你要求更多的UIThreads;)