WPF virtualizing big items
I´m binding a pretty huge collection of items to an ItemsControl. The ItemTemplate of the ItemsControl is set to a custom usercontrol rendering the data. The Ite开发者_如何学运维mControl is virtualized.
The problem now is that each usercontrol in the ItemsControl can become quite heigh. Its even possible that it becomes heigher than the actual screenheight. If that happens I´ve no chance to see the rest of the usercontrol because as soon as I scroll the next item in the collection is brought to the top of the screen and the only half shown item gets completly scrolled out of view. If I don´t use virtualization everything is obviously working fine.
Is there any way to get around this behavior and still be able to use virtualization?
There is a way around the behaviour, but it's not entirely pretty... basically, it's to implement your own virtualizing panel. As you correctly noticed, the behaviour of the built in panel is to draw from the top of the topmost item - you can't have half an item at the top of the screen. This, basically, is because it makes the virtualization code a lot lighter weight, and in most cases it's not a problem.
You can create your own panel (derive from VirtualizingPanel
) that doesn't have this restriction. It's not straightforward, but it's worthwhile for the results!
In your case, if all of the items are fixed size and beyond the size of the screen, you may find it's not quite so complicated - a lot of the complexity comes when items are variable sizes.
Does your ItemsControl's ScrollViewer have content scrolling Set?
Edit 2: As Dan meantioned, it appears as soon as you try to get smooth scrolling, you lose Virtualization. I'm not sure what your requirements are, but a potential workaround might be something like the following:
<Window x:Class="TestApp11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:l="clr-namespace:TestApp11"
Title="Window1" Height="200" Width="200">
<Grid>
<ItemsControl>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type ListBoxItem}">
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="160">
<Border Height="200" Width="140" BorderBrush="Red" BorderThickness="10" Margin="1" Background="Blue" />
</ScrollViewer>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizingStackPanel.VirtualizationMode="Recycling" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
<ContentElement />
</ItemsControl>
</Grid>
</Window>
Essentially, you can have the ItemTemplate wrap your UserControl Items inside a ScrollViewer. I didn't show it in my example, but you could bind the MaxHeight of the ScrollViewer (inside the ItemTemplate) to the the Height of your viewable area, and then the vertical scroll bar will only show up if your UserControl is too big to fit in the screen.
I can see where this might be too ugly of a solution to give to a customer however, in which case I think the only option is to go the route suggested by Dan.
精彩评论