2011-04-11 55 views
1

下面的代码为CompoundObjects然后加载字符串的分层集合。但不幸的是,它将字符串插入树的顶部而不是底部(这是我一直看到的行为)TreeView和复合数据的奇怪失序行为

我试图改变枚举器,通知器等等的顺序产生相同的结果。我已经(使用线程相同的代码),我预先加载它看起来正常的列表。

任何想法怎么回事?

CompoundObject.cs

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 
using System.Linq; 
using System.Text; 

namespace ComplexTreeViewLazyLoadingTest 
{ 
    public class CompoundObject : IEnumerable<object>, INotifyCollectionChanged 
    { 
     public string Name { get; set; } 
     public ObservableCollection<CompoundObject> objects { get; private set; } 
     public ObservableCollection<string> Items { get; private set; } 

     void OnChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      if (CollectionChanged != null) 
      App.Current.Dispatcher.Invoke((Action<object, NotifyCollectionChangedEventArgs>)((senderr, ee) => { 
       CollectionChanged(senderr, ee); 
      }), sender, e); 
     } 

     public CompoundObject(string name) 
     { 
      Name = name; 
      Items = new ObservableCollection<string>(); 
      objects = new ObservableCollection<CompoundObject>(); 

      Items.CollectionChanged += new NotifyCollectionChangedEventHandler(OnChanged); 
      objects.CollectionChanged += new NotifyCollectionChangedEventHandler(OnChanged); 
     } 


     public IEnumerator<object> GetEnumerator() 
     { 
      if (objects != null) foreach(var a in objects) yield return a; 
      if (Items != null) foreach (var a in Items) yield return a;   
      yield break; 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } 



     public event NotifyCollectionChangedEventHandler CollectionChanged; 

    } 



} 

MainWindow.xaml.cs

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.Threading; 

namespace ComplexTreeViewLazyLoadingTest 
{ 


    public partial class MainWindow : Window 
    { 

     CompoundObject c = new CompoundObject("Root"); 
     public MainWindow() 
     { 
      InitializeComponent(); 

      treeView.DataContext = c; 
      treeView.ItemsSource = c; 

      ThreadPool.QueueUserWorkItem(new WaitCallback(Update)); 

     } 


     void Update(object data) 
     { 


      for (int i = 0; i < 10; i++) 
      { 
       Application.Current.Dispatcher.Invoke((Action<CompoundObject>)((cc) => { 
        c.objects.Add(cc); 
       }), new CompoundObject("Object " + i)); 

       for (int j = 0; j < 5; j++) 
       { 
        Thread.Sleep(100); 
        Application.Current.Dispatcher.Invoke((Action<CompoundObject>)((cc) => 
        { 
         c.objects[i].objects.Add(cc); 
        }), new CompoundObject("subObject " + j)); 

       } 

      } 

      for (int i = 0; i < 8; i++) 
      { 
       Thread.Sleep(250); 
       Application.Current.Dispatcher.Invoke((Action<string>)((ii) => 
       { 
        c.Items.Add("Item " + ii); 
       }), i.ToString()); 
      } 



     } 

    } // MainWindow 



    public class DTS : DataTemplateSelector 
    { 
     public override DataTemplate SelectTemplate(object item, DependencyObject container) 
     { 
      FrameworkElement element = container as FrameworkElement; 

      if (element != null && item != null) 
      { 

       if (item is CompoundObject) 
       { 
        return element.FindResource("CompoundTemplate") as DataTemplate; 
       } 

       if (item is int) 
       { 
        return element.FindResource("DefaultTemplate") as DataTemplate; 
       } 
      } 



      return null; 
     } 
    } 


} 

MainWindow.xaml

<Window x:Class="ComplexTreeViewLazyLoadingTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:ComplexTreeViewLazyLoadingTest;assembly=" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 

     <local:DTS x:Key="DTS"/> 

     <HierarchicalDataTemplate x:Key="CompoundTemplate" ItemsSource="{Binding Path=.}"> 
      <TextBlock Text="{Binding Name}" /> 
     </HierarchicalDataTemplate> 

     <HierarchicalDataTemplate x:Key="DefaultTemplate" ItemsSource="{Binding Path=.}"> 
      <TextBlock Text="{Binding Path=.}" Background="Aqua" /> 
     </HierarchicalDataTemplate> 

    </Window.Resources> 


     <Grid> 


     <TreeView Name="treeView" ItemTemplateSelector="{StaticResource DTS}"/> 

    </Grid> 
</Window> 

回答

1

因为你合并两个集合,并直接订阅到CollectionChanged,变更通知对于子列表,而不是“组合拳”名单。这意味着当你真的希望它添加到列表的末尾时,你会得到一个'string added to'的通知。为了做到这一点,您需要订阅每个子集合的CollectionChanged并正确实现您自己的CollectionChanged回调(将第一个集合的Count添加到添加/删除字符串时报告的所有索引中。)

+0

,而不是100%确定如果你说我做了什么,但不知何故,我确实用你的答案解决了它(至少你指出我在正确的地方)。 NotifyCollectionChangedEventArgs被传递索引来添加项目。由于子集合确实知道彼此知道他们都通过相同的起始索引。我只是通过我自己的NotifyCollectionChangedEventArgs添加元素和NewStartIndex = -1,它总是将它添加到列表的底部。 – AbstractDissonance 2011-04-11 23:34:58

+0

这听起来像适用于您的特定情况,您可能会考虑通过并正确实施NotifyCollectionChanged的所有情况以提供“组合”收集视图。如果我理解正确,那么当前实现仅在您添加到列表末尾时才有效。 – 2011-04-12 14:01:58