2011-04-11 2 views
1

다음 코드는 CompoundObject에 대한 계층 적 컬렉션을로드 한 다음 문자열에 대한 계층 적 컬렉션을로드합니다. 하지만 안타깝게도 아래쪽에있는 문자열 대신에 문자열의 맨 위에 문자열을 삽입합니다. (항상 보았던 동작입니다.)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에 가입하고 있기 때문에, 변경 알림 대신 '결합'목록의 하위 목록에 대한 것입니다. 즉, 정말로 목록 끝에 추가하려고 할 때 '0에서 문자열 추가'라는 알림을 받게됩니다. 이 작업을 수행하려면 각 하위 컬렉션에 대해 CollectionChanged를 구독하고 자신의 CollectionChanged 콜백을 올바르게 구현해야합니다 (문자열 추가/제거시보고 된 모든 인덱스에 첫 컬렉션의 Count를 추가해야합니다).

+0

감사 100 % 확신하지 말라. 나는 네가 한 일을 말하는 것이지 어떻게 든 나는 그 말을 너의 대답으로 고쳤다. NotifyCollectionChangedEventArgs에는 항목을 추가 할 색인이 전달됩니다. 하위 컬렉션은 서로에 대해 알고 있기 때문에 둘 다 동일한 시작 인덱스를 전달합니다. 추가 된 요소와 함께 내 자신의 NotifyCollectionChangedEventArgs를 전달하고 NewStartIndex = -1은 항상 목록의 맨 아래에 추가합니다. – AbstractDissonance

+0

특정 상황에서이 방법이 효과가있는 것처럼 들리지만 NotifyCollectionChanged에 대한 모든 사례를 올바르게 구현하여 '조합 된'컬렉션보기를 제공하는 것이 좋습니다. 내가 올바르게 이해하면 현재 구현은 항상 목록의 끝에 추가하는 경우에만 작동합니다. –

관련 문제