Answered by:
TreeView VirtualizingStackPanel - problem with ScrollViewer

Question
-
Hello,
I have a problem concerning TreeView's VirtualizingStackPanel.
If ScrollViewer is not used, virtualization works fine.
But if I use ScrollViewer it does not work. Does any one know why? It does not matter if CanContenScroll is true or false, virtualization does not work.
Here is a ScrollViewer code (if you comment this code virtualization works):
<!-- Setters that break virtualization --> <Setter Property="TreeView.OverridesDefaultStyle" Value="True" /> <Setter Property="TreeView.Template"> <Setter.Value> <ControlTemplate TargetType="TreeView"> <ScrollViewer Focusable="False" CanContentScroll="True" Padding="4"> <ItemsPresenter HorizontalAlignment="Stretch"/> </ScrollViewer> </ControlTemplate> </Setter.Value> </Setter> <!-- End of setters that break virtualization -->
Here is complete xaml:
<Window x:Class="TreeViewTest.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TreeViewTest" Title="Window1" Height="600" Width="800" WindowState="Maximized"> <Window.Resources> <local:TreeData x:Key="ViewModel" /> <Style x:Key="TreeItemStyle" TargetType="{x:Type TreeViewItem}"> <Setter Property="TreeViewItem.IsExpanded" Value="True" /> </Style> <Style x:Key="ItemContentStyle" TargetType="{x:Type ContentControl}"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <Border BorderThickness="0,0,0,1" BorderBrush="Gray"> <StackPanel Background="LightGoldenrodYellow" Orientation="Horizontal" VerticalAlignment="Top" Margin="5"> <StackPanel Orientation="Vertical" Margin="2,0,0,0" VerticalAlignment="Top" MinWidth="60"> <TextBlock Text="Let's say this is the very wide control which must be stretched."/> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=Title}"/> </StackPanel> </StackPanel> </StackPanel> </Border> </DataTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="TreeViewStyle"> <Setter Property="TreeView.Background" Value="Transparent"/> <Setter Property="TreeView.SnapsToDevicePixels" Value="True" /> <!-- Setters that break virtualization --> <Setter Property="TreeView.OverridesDefaultStyle" Value="True" /> <Setter Property="TreeView.Template"> <Setter.Value> <ControlTemplate TargetType="TreeView"> <ScrollViewer Focusable="False" CanContentScroll="True" Padding="4"> <ItemsPresenter HorizontalAlignment="Stretch"/> </ScrollViewer> </ControlTemplate> </Setter.Value> </Setter> <!-- End of setters that break virtualization --> </Style> <HierarchicalDataTemplate x:Key="TreeTemplate" DataType="{x:Type local:TestTreeItemGroup}" ItemsSource="{Binding Path=Items}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Group: " /> <TextBlock Text="{Binding Path=Title}" /> </StackPanel> </HierarchicalDataTemplate> <DataTemplate x:Key="TreeItemTemplate" DataType="{x:Type local:TestTreeItem}"> <ContentControl Content="{Binding}" Style="{StaticResource ItemContentStyle}"> </ContentControl> </DataTemplate> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Grid Grid.Row="1"> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="8*" /> <RowDefinition Height="30" /> </Grid.RowDefinitions> <TextBlock Text="Upper Row" Grid.Row="0" /> <DockPanel Grid.Row="1"> <TreeView HorizontalContentAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Auto" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" ItemContainerStyle="{StaticResource TreeItemStyle}" Style="{StaticResource TreeViewStyle}" ItemsSource="{Binding Source={StaticResource ViewModel}, Path=Items}"> <TreeView.ItemTemplateSelector> <local:TreeTemplateSelector /> </TreeView.ItemTemplateSelector> </TreeView> </DockPanel> <GridSplitter Grid.Row="1" ResizeDirection="Rows" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="0" /> <Button Grid.Row="2" Content="Reload data" Click="Button_Click" /> </Grid> </Grid> </Window>
And code behind:
using System.Windows; using System.Windows.Controls; using System.ComponentModel; using System.Collections.ObjectModel; namespace TreeViewTest { public partial class Window1 : Window { public Window1() { InitializeComponent(); } internal TreeData ViewModel { get { return this.Resources["ViewModel"] as TreeData; } } private void Button_Click(object sender, RoutedEventArgs e) { ViewModel.LoadData(); } } class TestTreeItem : INotifyPropertyChanged { private string _Title; public string Title { get { return _Title; } set { _Title = value; RaisePropertyChanged("Title"); } } #region INotifyPropertyChanged Members protected void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; #endregion } class TestTreeItemGroup : TestTreeItem { public TestTreeItemGroup() { Items = new ObservableCollection<TestTreeItem>(); } public ObservableCollection<TestTreeItem> Items { get; set; } } class TreeData { public TreeData() { Items = new ObservableCollection<TestTreeItem>(); } public ObservableCollection<TestTreeItem> Items { get; set; } public void LoadData() { Items.Clear(); for (int j = 0; j < 5; j++) { TestTreeItemGroup group = new TestTreeItemGroup() { Title = string.Format("Group{0}", j + 1) }; Items.Add(group); for (int i = 0; i < 200; i++) { TestTreeItem item = new TestTreeItem() { Title = string.Format("Item{0}", i + 1) }; group.Items.Add(item); } } } } class TreeTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { FrameworkElement el = container as FrameworkElement; if (el == null) { return null; } object resource = null; if (item is TestTreeItemGroup) { resource = el.TryFindResource("TreeTemplate"); } else if (item is TestTreeItem) { resource = el.TryFindResource("TreeItemTemplate"); } return (resource != null) ? (DataTemplate)resource : base.SelectTemplate(item, container); } } }
Thanks in advanceFriday, November 21, 2008 10:58 AM
Answers
-
The following TreeView style works correctly for me:
<Style x:Key="TreeViewStyle">
<Setter Property="TreeView.Background" Value="Transparent"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="TreeView.SnapsToDevicePixels" Value="True" />
<Setter Property="TreeView.OverridesDefaultStyle" Value="True" />
<Setter Property="ItemsControl.ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="TreeView.Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<ScrollViewer Focusable="False" CanContentScroll="True" Padding="4">
<ItemsPresenter HorizontalAlignment="Stretch"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks
- Marked as answer by Cezary Wojcik Wednesday, November 26, 2008 9:28 AM
Wednesday, November 26, 2008 8:54 AM
All replies
-
Could you please send your test project to me at v-mazho at microsoft dot com for repro?
Thanks
Tuesday, November 25, 2008 5:45 AM -
Hello,
I sent the test project.
Best regardsTuesday, November 25, 2008 7:54 AM -
The following TreeView style works correctly for me:
<Style x:Key="TreeViewStyle">
<Setter Property="TreeView.Background" Value="Transparent"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="TreeView.SnapsToDevicePixels" Value="True" />
<Setter Property="TreeView.OverridesDefaultStyle" Value="True" />
<Setter Property="ItemsControl.ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="TreeView.Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<ScrollViewer Focusable="False" CanContentScroll="True" Padding="4">
<ItemsPresenter HorizontalAlignment="Stretch"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks
- Marked as answer by Cezary Wojcik Wednesday, November 26, 2008 9:28 AM
Wednesday, November 26, 2008 8:54 AM -
Hello,
This solves the problem, thanks.
Best regardsWednesday, November 26, 2008 9:29 AM