DataBinding是否反转了我的ObservableCollection的顺序?

时间:2012-06-07 21:43:57

标签: c# data-binding binding observablecollection

我有以下自定义可观察集合(代码部分来自Dean Chalk的博客http://www.deanchalk.me.uk/post/Thread-Safe-Dispatcher-Safe-Observable-Collection-for-WPF.aspx并略有改动):

public class ThreadSaveObservableCollection <T> : IList<T>, INotifyCollectionChanged  {

    private IList<T> collection;
    private Dispatcher uiDispatcher;
    private ReaderWriterLock rwLock;

    public ThreadSaveObservableCollection () {

        collection = new List<T>();
        rwLock = new ReaderWriterLock();
        uiDispatcher = Dispatcher.CurrentDispatcher;
    }

    public void Insert (int index, T item) {

        if (Thread.CurrentThread == uiDispatcher.Thread) {

            insert_(index, item);
        } else {

            uiDispatcher.BeginInvoke(new Action<int, T>(insert_), DispatcherPriority.Normal, new object[] {index, item});
        }
    }

    private void insert_ (int index, T item) {

        rwLock.AcquireWriterLock(Timeout.Infinite);

        collection.Insert(index, item);
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));

        rwLock.ReleaseWriterLock();
    }

    public IEnumerator<T> GetEnumerator () {

        rwLock.AcquireReaderLock(Timeout.Infinite);

        IEnumerator<T> enumerator = collection.GetEnumerator();

        rwLock.ReleaseReaderLock();

        return enumerator;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {

        rwLock.AcquireReaderLock(Timeout.Infinite);

        IEnumerator<T> enumerator = collection.GetEnumerator();

        rwLock.ReleaseReaderLock();

        return enumerator;
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    ... // the remaining methods of the IList<> interface

}

此外,我有一个ViewModel,它包含此类的实例:

public class ViewModel {

    private ThreadSaveObservableCollection<string> Collection {get; set;}

    public ViewModel () {
        Collection = new ThreadSaveObservableCollection<string>();
    }

    public void Insert (string item) {

        Collection.Insert(0, item);
    }

}

我在代码隐藏中应用数据绑定,因为我动态创建了名为“LogList”的相应WPF控件(普通的List控件):

wpfContainer.LogList.ItemsSource = viewModel.Collection;

除了相对于ViewModel的Collection对象中的项目反转wpf列表控件中的项目顺序这一事实外,一切正常。

使用语句Collection.Insert(0,intem)我希望在列表顶部添加新项目,但我得到的结果与使用Collection.Add(item)的结果相同。

当我在运行期间进入代码时,我可以验证我的Collection中的项目是否按正确顺序排列,但是在wpf list控件内的表面上,顺序被更改,即反转。

我做错了什么?

我想这个问题必须在数据绑定的某处找到,因为它是连接我的ObservableCollection和wpf控件的'wire',似乎正确的顺序进入了连线,而且不正确就是离开它。

可能它与IList接口的GetEnumerator()方法有关,因为wpf控件的ItemSource属性正在等待枚举器?

我不知道,我真的被卡住了......

提前感谢您的帮助......

2 个答案:

答案 0 :(得分:1)

你可以尝试这样做:

http://msdn.microsoft.com/en-us/library/ms653208.aspx

CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<object>() { item }, 0));

我认为这个事件就是问题所在。

答案 1 :(得分:1)

关于你的代码的几点说明:

  • 命名:ThreadSafe,而不是ThreadSave
  • 比赛条件:你正在获得一个锁来调用.GetEnumerator。然后释放锁,并返回该枚举器。这不安全,如果线程条件合适,将在运行时抛出异常。你应该在这里做的是在锁定时创建列表的副本,然后将枚举器返回到该副本。
  • ReaderWriterLock具有一些已知的性能,可伸缩性和容易出错的使用(例如重新入口)问题。请改用ReaderWriterLocksSlim
  • 这里的整个想法是将所有操作封送到UI线程。如果UI线程上发生了所有事情,则根本不需要任何锁定。

最后,我建议使用其中一个thread-safe ObservableCollections而不是重新发明轮子。