Wal*_*mer 4 wpf scrollviewer controltemplate virtualizingstackpanel
我有一个列表框,里面有很多渲染成本很高的项目。然而,VirtualizingStackPanel 通过只渲染可见项来处理这个问题。我想覆盖 ScrollViewer 的控件模板,因为默认的控件模板在水平和垂直滚动条之间有灰色矩形。我只是复制了微软提供的一个(ScrollViewer ControlTemplate Example),它没有灰色矩形问题。
然而,这个控制模板通过给 VirtualizingStackPanel 无限的高度来禁用虚拟化。这意味着 VirtualizingStackPanel 将呈现所有项目,因为它认为所有项目都是可见的。
在下面的演示代码中,我在列表框中显示了 10000 个项目。我通过比较运行它与 ScrollViewer 样式和没有它来验证问题。有了它,演示运行得非常慢,调整大小需要几秒钟。没有样式它非常快。我输出了一些关于 VirtualizingStackPanel 的信息来证明我的观点:
没有 ScrollViewer 样式(注释掉 XAML 中的样式):
ViewportHeight: 8
ExtentHeight: 10000
ActualHeight: 245
IsVirtualizing: True
VirtualizationMode: Standard
使用 ScrollViewer 样式:
ViewportHeight: 0
ExtentHeight: 0
ActualHeight: 272766.666666707
IsVirtualizing: True
VirtualizationMode: Standard
知道如何为不会与虚拟化混淆的 ScrollViewer 编写控件模板吗?
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>
Run Code Online (Sandbox Code Playgroud)
后面的代码:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
此 ScrollViewer 样式是从 Blend 4 复制的,在输出窗口中看起来不错
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>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4100 次 |
| 最近记录: |