locked
TreeView VirtualizingStackPanel - problem with ScrollViewer RRS feed

  • 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(thisnew PropertyChangedEventArgs(propertyName));  
                }  
            }  
     
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion  
        }  
     
        class TestTreeItemGroup : TestTreeItem  
        {  
            public TestTreeItemGroup()  
            {  
                Items = new ObservableCollection<TestTreeItem>();  
            }  
     
            public ObservableCollection<TestTreeItem> Items { getset; }  
        }  
     
        class TreeData  
        {  
            public TreeData()  
            {  
                Items = new ObservableCollection<TestTreeItem>();  
            }  
     
            public ObservableCollection<TestTreeItem> Items { getset; }  
     
            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 advance
    Friday, 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 regards
    Tuesday, 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 regards
    Wednesday, November 26, 2008 9:29 AM