TreeView和复合数据的奇怪乱序行为

时间:2011-04-11 14:34:42

标签: wpf

以下代码加载了CompoundObjects的分层集合,然后是字符串。但不幸的是,它将字符串插入树的顶部而不是底部(这是我一直看到的行为。

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

有什么想法吗?

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 个答案:

答案 0 :(得分:1)

因为您正在组合两个集合并直接订阅CollectionChanged,所以更改通知是针对子列表而不是“组合”列表。这意味着当您真正想要在列表末尾添加时,您将收到“字符串添加为0”的通知。为了使这项工作,您需要为每个子集合订阅CollectionChanged并正确实现您自己的CollectionChanged回调(将第一个集合的Count添加到添加/删除字符串时报告的所有索引。)