我最近遇到了虚拟化问题,我已将其缩小到以下代码。
虚拟化在以下代码段中不起作用的原因是由于孩子没有特定的高度。所以我的猜测是它会永远扩展并且虚拟化会中断。
给孩子一个特定的高度可以解决问题,但是当我想要一个滚动条时,界面会变成两个难看的滚动条,滚动浏览由项目控件生成的整个内容(如果是孩子的话)。 / p>
我的问题是,这可能吗?如果是这样我怎么能实现这个目标?不知怎的,孩子需要在不破坏虚拟化的情况下计算自身的大小。似乎设置*的高度不起作用。
MainWindow.xaml
<Window x:Class="WpfItemsControlVirtualization.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" >
<Window.Resources>
<ResourceDictionary>
<!--Virtualised ItemsControl-->
<Style x:Key="ItemsControlVirtialisedStyle" TargetType="ItemsControl">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Go" Click="ButtonBase_OnClick"/>
<Button Grid.Row="1" Content="Expand" Click="ButtonBase_OnClick2"/>
<Expander Grid.Row="2" >
<ItemsControl ItemsSource="{Binding Collection}" Style="{StaticResource ItemsControlVirtialisedStyle}" VirtualizingPanel.ScrollUnit="Pixel">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<!-- <RowDefinition Height="*"></RowDefinition> --> <!-- VIRTUALIZATION BREAK -->
<RowDefinition Height="500"></RowDefinition>
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding Collection}" Style="{StaticResource ItemsControlVirtialisedStyle}" VirtualizingPanel.ScrollUnit="Pixel">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Test}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</Grid>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfItemsControlVirtualization
{
/// <summary>
/// Implements the INotifyPropertyChanged interface for data binding purposes.
/// </summary>
public abstract class ViewModelBase : INotifyPropertyChanged, INotifyPropertyChanging
{
#region Abstract
public void AlertPropertyChanging(string propertyName)
{
OnPropertyChanging(propertyName);
}
public void AlertPropertyChanged(string propertyName)
{
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected void OnPropertyChanging(string propertyName)
{
var handler = PropertyChanging;
if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
OnPropertyChanging(propertyName);
field = value;
OnPropertyChanged(propertyName);
return true;
}
protected void Set(Action action, string propertyName = null)
{
OnPropertyChanging(propertyName);
if (action != null) action();
OnPropertyChanged(propertyName);
}
#endregion
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
#endregion Implementation of INotifyPropertyChanged
#region Implementation of INotifyPropertyChanging
public event PropertyChangingEventHandler PropertyChanging;
#endregion Implementation of INotifyPropertyChanging
}
public class MySubDataTest : ViewModelBase
{
public MySubDataTest()
{
}
public string Test
{
get { return "SubTest"; }
set { }
}
public bool IsExpanded
{
get { return m_IsExpanded; }
set { Set(ref m_IsExpanded, value); }
}
private bool m_IsExpanded = false;
}
public class MyDataTest : ViewModelBase
{
public MyDataTest()
{
int test = 1000;
for (int i = 0; i < test; i++)
{
Collection.Add(new MySubDataTest());
}
}
public string Test
{
get { return "Test"; }
set { }
}
public bool IsExpanded
{
get { return m_IsExpanded; }
set { Set(ref m_IsExpanded, value); }
}
private bool m_IsExpanded = false;
public ObservableCollection<MySubDataTest> Collection
{
get { return m_Collection; }
}
ObservableCollection<MySubDataTest> m_Collection = new ObservableCollection<MySubDataTest>();
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<MyDataTest> Collection
{
get { return m_Collection; }
}
ObservableCollection<MyDataTest> m_Collection = new ObservableCollection<MyDataTest>();
private void ButtonBase_OnClick(object _sender, RoutedEventArgs _e)
{
int count = 1;
for (var i = 0; i < count; i++)
{
Collection.Add(new MyDataTest());
}
DataContext = this;
}
private void ButtonBase_OnClick2(object _sender, RoutedEventArgs _e)
{
foreach (MyDataTest test in Collection)
{
foreach (MySubDataTest sub in test.Collection)
{
sub.IsExpanded = true;
}
test.IsExpanded = true;
}
}
}
}
提前谢谢。
答案 0 :(得分:-1)
没有真正开箱即用的方法。我最终的方式是完全自定义TreeView的模板,因为它支持层次虚拟化。
你可以使用它和DataTemplates一起使用递归的ItemsTemplates产生相同的结果,并且效率更高。
答案 1 :(得分:-1)
这里没问题。外部ItemTemplate
的{{1}}本身包含ItemsControl
。在ItemsControl
中,每个元素都是渲染的。虚拟化可能有助于不渲染非可见元素,但第一个元素部分可见,因此它不符合虚拟化条件,并且完全呈现无限高度。