2013-12-19 5 views
0

Как упоминалось в названии, у меня есть большое количество элементов в иерархической структуре, я хочу отображать их в элементе управления TreeView, помимо времени загрузки, на начать работать неплохо, но чем длиннее работает с древовидной структурой (проверка флажков, расширение, сжатие, выбор), тем медленнее это получается, вот пример кода (количество элементов выбрано таким образом, что они представляет собой реалистичное максимальное количество элементов для нормального использования, если вы бежите из памяти просто настроить количество созданных элементов)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, поэтому даже хорошее понимание последнего было бы очень полезно

ответ

0

Поскольку у вас так много создаваемых узлов, попробуйте настроить виртуализацию на дереве.

<TreeView VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"> 
Смежные вопросы