在工作了几分钟后,树视图变得很慢

时间:2013-12-19 16:23:56

标签: c# wpf performance treeview

如标题中所提到的,我在层次结构中有大量项目,我想在树视图控件中显示它们,除了加载时间之外,在开始时性能还不错,但是工作时间越长使用树视图(检查复选框,扩展,收缩,选择)得到的速度越慢,这里是示例代码(以这种方式选择元素的数量,它们表示正常使用的实际最大元素数,如果你的内存耗尽只是调整创建项目的数量)

XAML代码:

<Window x:Class="testLargeContourTree.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid Grid.Column="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TreeView  Grid.Row="0" x:Name="treeView" ItemsSource="{Binding Children}">
                <!--<TreeView.Resources>
                    <Style TargetType="TreeViewItem">
                        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                    </Style>
                </TreeView.Resources>-->
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                        <StackPanel Orientation="Horizontal">
                            <CheckBox IsChecked="{Binding IsChecked}" />
                            <TextBlock Text="{Binding Name}" />
                        </StackPanel>                  
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
            <Button Grid.Row="1" Content="Start" />
            <Button Grid.Row="2" Content="Stop" />
            <Button Grid.Row="3" Content="Move Up" />
            <Button Grid.Row="4" Content="Move Down" />
        </Grid>
        <TextBlock Grid.Column="1" x:Name="textOut" />
    </Grid>
</Window>

C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Windows.Threading;


namespace testLargeContourTree
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MyTreeViewItem _itemCollection;

        public MainWindow()
        {
            InitializeComponent();

            _itemCollection = new MyTreeViewItem();
            MyTreeViewItem year;
            MyTreeViewItem month;
            MyTreeViewItem day;
            MyTreeViewItem job;
            MyTreeViewItem contour;
            MyTreeViewItem segment;
            Int32 numberOfJobs = 0;
            Int32 numberOfSegments = 0;
            for (Int32 i = 0; i < 2; i++)
            {
                year = new MyTreeViewItem(String.Format("{0}", 2013 + i));
                for (Int32 j = 0; j < 12; j++)
                {
                    month = new MyTreeViewItem(String.Format("{0}", (Months)j));
                    for (Int32 k = 0; k < 10; k++)
                    {
                        day = new MyTreeViewItem(String.Format("{0}", k + 1));
                        for (Int32 l = 0; l < 20; l++)
                        {
                            job = new MyTreeViewItem(String.Format("Job {0}", numberOfJobs + 1));
                            for (Int32 m = 0; m < 50; m++)
                            {
                                contour = new MyTreeViewItem(String.Format("Contour {0}", m + 1));
                                for (Int32 n = 0; n < 100; n++)
                                {
                                    segment = new MyTreeViewItem(String.Format("Segment {0}", n + 1));
                                    contour.AddChild(segment);
                                    numberOfSegments++;
                                }
                                job.AddChild(contour);
                            }
                            day.AddChild(job);
                            numberOfJobs++;
                        }
                        month.AddChild(day);
                    }
                    year.AddChild(month);
                }
                _itemCollection.AddChild(year);
            }
            treeView.DataContext = _itemCollection;
            textOut.Text = String.Format("number of segments: {0}", numberOfSegments + 1);
        }
    }

    public enum Months
    {
        Jannuary,
        February,
        March,
        April,
        May,
        June,
        July,
        August,
        September,
        October,
        November,
        December
    }


    public class MyTreeViewItem : INotifyPropertyChanged
    {
        private String _name;
        public String Name
        {
            get { return _name; }
            set { _name = value; OnPropertyChanged("Name"); }
        }
        public ObservableCollection<MyTreeViewItem> Children { get; set; }
        private Boolean _isSelected;
        public Boolean IsSelected
        {
            get { return _isSelected; }
            set { _isSelected = value; OnPropertyChanged("IsSelected"); }
        }
        private Boolean _isExpanded;
        public Boolean IsExpanded
        {
            get { return _isExpanded; }
            set { _isExpanded = value; OnPropertyChanged("IsExpanded"); }
        }
        private Boolean _isChecked;
        public Boolean IsChecked
        {
            get { return _isChecked; }
            set 
            { 
                _isChecked = value; 
                OnPropertyChanged("IsChecked");
                if (Children != null)
                {
                    ObservableCollection<MyTreeViewItem> children = Children;
                    foreach (MyTreeViewItem child in children)
                    {
                        child.IsChecked = value;
                    }
                }
            }
        }

        public MyTreeViewItem()
        {
            IsSelected = false;
            IsExpanded = false;
            IsChecked = false;
            Name = "";
            Children = new ObservableCollection<MyTreeViewItem>();
        }

        public MyTreeViewItem(String name) : this()
        {
            Name = name;
        }

        public void AddChild(MyTreeViewItem item)
        {
            Children.Add(item);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我知道大量内存使用和大量元素,但是,我希望在使用过程中性能大致相同

我在某处读到了如果没有正确使用inotifypropertychanged会有潜在的内存泄漏,我试图按照提供的建议,但它没有改变这种行为,除了接缝有足够的内存留下

所以我要求任何关于如何稳定表现的建议

我的猜测是,当父元素被展开时,元素会按需加载,但如果它们被约束则不会被卸载,但是我对wpf树视图的背景机制没有足够的了解,所以即使是好的洞察后者将非常有帮助

1 个答案:

答案 0 :(得分:0)

由于您创建了如此多的节点,请尝试在树上设置虚拟化。

<TreeView VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">