我的上一个问题已经太久了,所以这里是一个新问题!
我在滚动期间遇到虚拟化WPF TreeView的性能问题。假设我的TreeViewItems下面有任意复杂的控件可能需要很长时间 - 比方说10ms - 需要测量。向下滚动TreeView会很快变得非常迟缓,因为为每个滚动单元调用布局传递。
在这种情况下,您有什么想要顺利滚动? 我尝试了两种不同的方法,但我遇到了两个问题。
第一个是缓冲最后一个MeasureOverride结果并使用它而不是再次调用MeasureOverride,除非更改大小。只要我在树中只有一个层次结构级别,它就可以正常工作。但是一旦我得到更多,一些项目不会被渲染(尽管大小被正确保留)。使缓冲区无效不会成为问题。
第二个是在滚动期间替换了TreeViewItems下的ControlTemplate,这要归功于Trigger,使用ControlTemplate可以非常快速地进行渲染。可悲的是,当我停止滚动已经附加在逻辑树中的regargind项目时,我会遇到奇怪的异常。
最后,我不在多线程环境中,因此无法使用异步绑定。 :(
这是我想改进的树的一个非常小的例子(它是实现我的第一个想法的那个),我只是在用于渲染我的Items的ContentControl的MeasureOverride中放入一个Thread.Sleep(10)。
public class Item
{
public string Index { get; set; }
public Item Parent { get; set; }
public IEnumerable<Item> Items
{
get
{
if (Parent == null)
{
for (int i = 0; i < 10; i++)
{
yield return new Item() { Parent = this, Index = this.Index + "." + i.ToString() };
}
}
}
}
}
public class HeavyControl : ContentControl
{
protected override Size MeasureOverride(Size constraint)
{
Thread.Sleep(10);
return base.MeasureOverride(constraint);
}
}
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<Item> Items
{
get
{
for (int i = 0; i < 20; i++)
{
yield return new Item() { Index = i.ToString() };
}
}
}
}
public class MyTreeView : TreeView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new MyTreeViewItem();
}
}
public class MyTreeViewItem : TreeViewItem
{
static MyTreeViewItem()
{
MyTreeViewItem.IsExpandedProperty.OverrideMetadata(typeof(MyTreeViewItem), new FrameworkPropertyMetadata(true));
}
public Size LastMeasure
{
get { return (Size)GetValue(LastMeasureProperty); }
set { SetValue(LastMeasureProperty, value); }
}
// Using a DependencyProperty as the backing store for LastMeasure. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LastMeasureProperty =
DependencyProperty.Register("LastMeasure", typeof(Size), typeof(MyTreeViewItem), new UIPropertyMetadata(default(Size)));
protected override Size MeasureOverride(Size constraint)
{
if (LastMeasure != default(Size))
{
if (this.VisualChildrenCount > 0)
{
UIElement visualChild = (UIElement)this.GetVisualChild(0);
if (visualChild != null)
{
visualChild.Measure(constraint);
}
}
return LastMeasure;
}
else
{
LastMeasure = base.MeasureOverride(constraint);
return LastMeasure;
}
}
protected override DependencyObject GetContainerForItemOverride()
{
return new MyTreeViewItem();
}
}
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Items}">
<local:HeavyControl>
<TextBlock FontSize="20" FontWeight="Bold" Text="{Binding Index}" />
</local:HeavyControl>
</HierarchicalDataTemplate>
</Window.Resources>
<local:MyTreeView x:Name="treeView" VirtualizingStackPanel.IsVirtualizing="True" ItemsSource="{Binding Items}" />
</Window>
答案 0 :(得分:2)
我会尝试修复第二种方法中的错误。