我正在使用 itemscontrol 来保存许多不同大小的控件。由于需要显示的控件数量,我决定启用虚拟化(在某些情况下“加载”控件需要一秒钟左右的时间,我真的需要将它们显示在一个长列表中,而不是使用某种崩溃)。
下面是我所拥有的一个简单测试(我正在使用这里提到的反射黑客)。问题是垂直滚动条上的拇指在您拖动时会更新,我认为这是有道理的,因为滚动查看器本身会随着新控件的出现而即时更新,但我想知道是否有解决方案?
是否可以进行虚拟化、基于像素的滚动和大小反映所有控件而不仅仅是其处理的控件的拇指?
public class A { public double Height { get; set; } };
public partial class MainWindow : Window
{
public List<A> Data { get; set; }
public MainWindow()
{
var r = new Random();
Data = new List<A>();
for (int i = 0; i < 250; ++i)
{
Data.Add(new A() { Height = r.Next(10, 500) });
}
DataContext = this;
InitializeComponent();
}
}
<ItemsControl ItemsSource="{Binding Data}" VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel local:PixelBasedScrollingBehavior.IsEnabled="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<UniformGrid Columns="4">
<Label Content="label" Height="{Binding Height}"/>
<TextBox />
<UniformGrid Rows="2">
<Button />
<Button />
</UniformGrid>
<Slider/>
</UniformGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
作为次要问题。为了查看禁用虚拟化时花费了这么长时间,我从 StackPanel 派生了 Measure/Arrange 函数,发现所有加载时间都花在了这些函数上。在我的情况下,测量时间为 600 毫秒,排列时间为 200 毫秒。WPF 分析工具也指出布局是杀手。这似乎是一个非常长的时间。诚然,像这样渲染 250 个控件(根据 Snoop 是 10k 个元素)并不是您最想做的事情,但是任何人都可以解释为什么需要这么长时间吗?是否在创建新控件时更新整个布局?我已经为 Slider 控件尝试了一些自定义模板,以尝试减少它使用的元素的数量并取得了一些成功,但后来我失去了功能。