VirtualizingStackPanel smette di funzionare quando l'override del modello di controllo di default per ScrollViewer

StackOverflow https://stackoverflow.com/questions/4219768

Domanda

Ho una casella di riepilogo con un sacco di oggetti che sono costosi per il rendering. Tuttavia il VirtualizingStackPanel si prende cura di che, solo rendendo gli elementi visibili. Voglio ignorare il modello di controllo per ScrollViewer poiché quello di default ha rettangolo grigio tra la barra di scorrimento orizzontale e verticale. Io ho semplicemente copiato quello fornito da Microsoft ( ScrollViewer ControlTemplate esempio ) che non hanno il problema rettangolo grigio.

Questa ControlTemplate però disabilita virtualizzazione dando l'altezza infinita VirtualizingStackPanel. Ciò significa che il VirtualizingStackPanel renderà tutti gli elementi, dal momento che pensa che tutti gli elementi sono visibili.

Nel seguito demo codice che mostrano 10000 elementi in una casella di riepilogo. Verifico il problema attraverso il confronto eseguendolo con lo stile ScrollViewer e senza di essa. Con esso viene eseguito il demo molto lento, il ridimensionamento vogliono parecchi secondi. Senza lo stile è molto veloce. Uscita ho alcune informazioni circa la VirtualizingStackPanel per dimostrare il mio punto:

Senza lo stile ScrollViewer (Commento fuori lo stile nel XAML):

  

ViewportHeight: 8
  ExtentHeight: 10000
  ActualHeight: 245
  IsVirtualizing: True
  VirtualizationMode: Standard

Con lo stile ScrollViewer:

  

ViewportHeight: 0
  ExtentHeight: 0
  ActualHeight: 272766,666,666707 millions
  IsVirtualizing: True
  VirtualizationMode: Standard

Qualsiasi idea di come scrivere un modello di controllo per uno ScrollViewer che non pasticciare con la virtualizzazione?

XAML:

<Window x:Class="VirtualTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>

        <Style x:Key="{x:Type ScrollViewer}" TargetType="{x:Type ScrollViewer}">
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <ScrollContentPresenter Grid.Row="0" Grid.Column="0" />
                            <ScrollBar 
                                Name="PART_VerticalScrollBar" 
                                Grid.Row="0" Grid.Column="1" 
                                Value="{TemplateBinding VerticalOffset}" 
                                Maximum="{TemplateBinding ScrollableHeight}" 
                                ViewportSize="{TemplateBinding ViewportHeight}" 
                                Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
                            <ScrollBar 
                                Name="PART_HorizontalScrollBar" 
                                Orientation="Horizontal" 
                                Grid.Row="1" Grid.Column="0" 
                                Value="{TemplateBinding HorizontalOffset}" 
                                Maximum="{TemplateBinding ScrollableWidth}" 
                                ViewportSize="{TemplateBinding ViewportWidth}" 
                                Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>

    <Grid>
        <ListBox 
            ItemsSource="{Binding Numbers}"
            ScrollViewer.ScrollChanged="ListBox_ScrollChanged"
            Background="Orange">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Red" BorderThickness="2" Margin="5">
                        <TextBlock Text="{Binding .}" Width="400"/>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate> 
        </ListBox>

    </Grid>
</Window>

Codice dietro:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace VirtualTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            DataContext = this;
        }

        public IEnumerable<double> Numbers
        {
            get
            {
                for (int i = 0; i < 10000; i++)
                {
                    yield return i;
                }
            }
        }

        private void ListBox_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            ListBox listBox = sender as ListBox;
            VirtualizingStackPanel virtualizingStackPanel = FindVirtualizingStackPanel(listBox);                             
            Debug.WriteLine("ViewportHeight: " + virtualizingStackPanel.ViewportHeight);
            Debug.WriteLine("ExtentHeight: " + virtualizingStackPanel.ExtentHeight);
            Debug.WriteLine("ActualHeight: " + virtualizingStackPanel.ActualHeight);
            Debug.WriteLine("IsVirtualizing: " + VirtualizingStackPanel.GetIsVirtualizing(virtualizingStackPanel));
            Debug.WriteLine("VirtualizationMode: " + VirtualizingStackPanel.GetVirtualizationMode(virtualizingStackPanel));
        }

        private VirtualizingStackPanel FindVirtualizingStackPanel(Visual visual)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
            {
                Visual child = VisualTreeHelper.GetChild(visual, i) as Visual;

                if (child != null)
                {
                    if (child is VirtualizingStackPanel)
                    {
                        return child as VirtualizingStackPanel;
                    }

                    VirtualizingStackPanel found = FindVirtualizingStackPanel(child);
                    if (found != null)
                    {
                        return found;
                    }
                }
            }

            return null;
        }
    }
}
È stato utile?

Soluzione

Questo stile ScrollViewer è copiato da Blend 4 e si guarda bene nella finestra di output

  

ViewportHeight: 10
  ExtentHeight: 10000
  ActualHeight: 308
  IsVirtualizing: True
  VirtualizationMode: Standard

<Style TargetType="{x:Type ScrollViewer}">
    <Style.Triggers>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </Style.Triggers>
    <Setter Property="Template" Value="{DynamicResource ScrollViewerControlTemplate1}"/>
</Style>
<ControlTemplate x:Key="ScrollViewerControlTemplate1" TargetType="{x:Type ScrollViewer}">
    <Grid x:Name="Grid" Background="{TemplateBinding Background}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/>
        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
        <ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
        <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
    </Grid>
</ControlTemplate>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top