Wpf TreeView和复合数据的奇怪无序行为
下面的代码加载一个层次结构集合,用于组合对象的集合,然后加载字符串的集合。但不幸的是,它在树的顶部而不是底部插入字符串(这是我一直看到的行为) 我尝试更改枚举器、通知器等的顺序,所有这些都会产生相同的结果。我已经预加载了列表,它看起来很正常(在线程中使用相同的代码) 你知道怎么回事吗 CompoundObject.csWpf TreeView和复合数据的奇怪无序行为,wpf,Wpf,下面的代码加载一个层次结构集合,用于组合对象的集合,然后加载字符串的集合。但不幸的是,它在树的顶部而不是底部插入字符串(这是我一直看到的行为) 我尝试更改枚举器、通知器等的顺序,所有这些都会产生相同的结果。我已经预加载了列表,它看起来很正常(在线程中使用相同的代码) 你知道怎么回事吗 CompoundObject.cs using System; using System.Collections.Generic; using System.Collections.ObjectModel; usi
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;
}
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Collections.Specialized;
使用System.Linq;
使用系统文本;
命名空间ComplexTreeViewLazyLoadingTest
{
公共类CompoundObject:IEnumerable,INotifyCollectionChanged
{
公共字符串名称{get;set;}
公共ObservableCollection对象{get;private set;}
公共可观测集合项{get;private set;}
更改后无效(对象发送方,NotifyCollectionChangedEventArgs e)
{
如果(CollectionChanged!=null)
App.Current.Dispatcher.Invoke((操作)((senderr,ee)=>{
收款已更改(发送人,ee);
}),发送者,e);
}
公共复合对象(字符串名称)
{
名称=名称;
Items=新的ObservableCollection();
对象=新的ObservableCollection();
Items.CollectionChanged+=新通知collectionchangedventhadler(一旦更改);
objects.CollectionChanged+=新的NotifyCollectionChangedEventHandler(OnChanged);
}
公共IEnumerator GetEnumerator()
{
如果(objects!=null)foreach(objects中的var a)产生返回值;
如果(Items!=null)foreach(Items中的var a)返回a;
屈服断裂;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator(){return GetEnumerator();}
公共事件通知CollectionChangedEventHandler 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;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
使用系统线程;
命名空间ComplexTreeViewLazyLoadingTest
{
公共部分类主窗口:窗口
{
CompoundObject c=新的CompoundObject(“根”);
公共主窗口()
{
初始化组件();
treeView.DataContext=c;
treeView.ItemsSource=c;
QueueUserWorkItem(新的WaitCallback(更新));
}
无效更新(对象数据)
{
对于(int i=0;i<10;i++)
{
Application.Current.Dispatcher.Invoke((操作)((cc)=>{
c、 对象。添加(cc);
}),新的复合对象(“对象”+i));
对于(int j=0;j<5;j++)
{
睡眠(100);
Application.Current.Dispatcher.Invoke((操作)((cc)=>
{
c、 objects[i].objects.Add(cc);
}),新的复合对象(“子对象”+j));
}
}
对于(int i=0;i<8;i++)
{
睡眠(250);
Application.Current.Dispatcher.Invoke((操作)((ii)=>
{
c、 项目。添加(“项目”+ii);
}),i.ToString());
}
}
}//主窗口
公共类DTS:DataTemplateSelector
{
公共覆盖数据模板SelectTemplate(对象项,DependencyObject容器)
{
FrameworkElement=容器作为FrameworkElement;
if(元素!=null&&item!=null)
{
如果(项为复合对象)
{
返回元素.FindResource(“CompoundTemplate”)作为DataTemplate;
}
如果(项目为int)
{
返回元素.FindResource(“DefaultTemplate”)作为DataTemplate;
}
}
返回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>
因为您要合并两个集合并直接订阅已更改的集合,所以更改通知是针对子列表的,而不是针对“合并”列表。这意味着您将收到一个“字符串已添加到0”的通知,而实际上您希望将其添加到列表的末尾。为了使此操作有效,您需要为每个子集合订阅CollectionChanged,并正确实现您自己的CollectionChanged回调(将第一个集合的计数添加到添加/删除字符串时报告的所有索引中。)因为您要合并两个集合并直接订阅已更改的集合,所以更改通知是针对子列表的,而不是针对“合并”列表。这意味着您将收到一个通知,当您确实希望将其添加到列表末尾时,会在0处添加一个“字符串”。为了实现此功能,您需要使用子列表抄录到每个子集合的CollectionChanged,并正确执行您自己的CollectionChanged回调(将第一个集合的计数添加到添加/删除字符串时报告的所有索引中)。谢谢,不100%确定您是否说了我所做的,但不知怎的,我用您的答案修复了它(至少您指出了正确的位置).NotifyCollectionChangedEventArgs被传递给要将项目添加到的索引。由于子集合相互了解,因此它们都