Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 优化WPF 4.0树视图滚动性能_C#_.net_Wpf_Wpf 4.0 - Fatal编程技术网

C# 优化WPF 4.0树视图滚动性能

C# 优化WPF 4.0树视图滚动性能,c#,.net,wpf,wpf-4.0,C#,.net,Wpf,Wpf 4.0,我已经很久没问上一个问题了,所以这里有一个新问题 我在滚动过程中遇到虚拟化WPF树视图的性能问题。假设我的TreeView项下有任意复杂的控件,需要很长时间(比如说10毫秒)才能测量。向下滚动TreeView会很快变得非常滞后,因为每个向下滚动单元都会调用布局过程 在这种情况下,您有什么想法来实现平滑滚动? 我尝试了两种不同的方法,但都有问题 第一个是缓冲最后一个MeasureOverride结果,并使用它,而不是再次调用MeasureOverride,除非大小发生变化。只要我在树中只有一个层次

我已经很久没问上一个问题了,所以这里有一个新问题


我在滚动过程中遇到虚拟化WPF树视图的性能问题。假设我的TreeView项下有任意复杂的控件,需要很长时间(比如说10毫秒)才能测量。向下滚动TreeView会很快变得非常滞后,因为每个向下滚动单元都会调用布局过程

在这种情况下,您有什么想法来实现平滑滚动? 我尝试了两种不同的方法,但都有问题

第一个是缓冲最后一个MeasureOverride结果,并使用它,而不是再次调用MeasureOverride,除非大小发生变化。只要我在树中只有一个层次结构级别,它就可以工作。但当我得到更多时,一些项目就不会被渲染(尽管大小已正确保留)。使缓冲区无效不是问题

第二个是在滚动过程中使用触发器替换treeViewItems下控件的ControlTemplate,使用ControlTemplate快速渲染。遗憾的是,当我停止滚动逻辑树中已经附加的项目时,我会遇到奇怪的异常

最后,我不在多线程环境中,因此无法使用异步绑定:(

这是我想改进的树的一个很小的例子(这是实现我第一个想法的树),我只是在用于呈现我的项目的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();
    }
}
公共类项目
{
公共字符串索引{get;set;}
公共项父项{get;set;}
公共数字项目
{
得到
{
如果(父项==null)
{
对于(int i=0;i<10;i++)
{
产生返回新项(){Parent=this,Index=this.Index+“+i.ToString()};
}
}
}
}
}
公共类重控件:ContentControl
{
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
睡眠(10);
返回基准。测量超越(约束);
}
}
/// 
///Logique d'interaction pour main window.xaml
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DataContext=this;
}
公共数字项目
{
得到
{
对于(int i=0;i<20;i++)
{
产生返回新项(){Index=i.ToString()};
}
}
}
}
公共类MyTreeView:TreeView
{
受保护的覆盖依赖对象GetContainerForItemOverride()
{
返回新的MyTreeViewItem();
}
}
公共类MyTreeView项目:TreeView项目
{
静态MyTreeViewItem()
{
MyTreeViewItem.IsExpandedProperty.OverrideMetadata(typeof(MyTreeViewItem),新框架属性ymetadata(true));
}
公共尺寸
{
获取{return(Size)GetValue(lastmasureproperty);}
set{SetValue(lastmasureproperty,value);}
}
//使用DependencyProperty作为LastMeasure的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性LastMeasureProperty=
DependencyProperty.Register(“LastMeasure”、typeof(大小)、typeof(MyTreeViewItem)、new UIPropertyMetadata(默认大小));
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
如果(LastMeasure!=默认值(大小))
{
如果(this.VisualChildrenCount>0)
{
UIElement visualChild=(UIElement)this.GetVisualChild(0);
如果(visualChild!=null)
{
视觉儿童测量(约束);
}
}
返回测量值;
}
其他的
{
LastMeasure=基础。测量超越(约束);
返回测量值;
}
}
受保护的覆盖依赖对象GetContainerForItemOverride()
{
返回新的MyTreeViewItem();
}
}
main window.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>

我将尝试修复第二种方法中的错误

  • 为树的每个节点/项指定一个唯一的键
  • 拥有保存每个节点/项中的控件的字典
  • 滚动时(甚至在不聚焦时),只需在树中显示数据的文本/简单表示
  • 聚焦节点/项后,使用唯一键将简单表示替换为字典中的适当控件
  • 当I节点/项失去焦点时,将其恢复为简单表示,因为更改仍存储在引用控件的字典值中

“假设我的TreeView项下有任意复杂的控件,需要很长时间(比如10毫秒)才能测量”->为什么这些控件需要时间来测量?优化这些控件并从根本上解决问题不是更简单吗?不幸的是,这是不可能的。这些控件已尽可能优化,有些控件将持续大约5到10毫秒来测量。