Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 数据绑定颠倒了我的可观察收集的顺序?_C#_Data Binding_Binding_Observablecollection - Fatal编程技术网

C# 数据绑定颠倒了我的可观察收集的顺序?

C# 数据绑定颠倒了我的可观察收集的顺序?,c#,data-binding,binding,observablecollection,C#,Data Binding,Binding,Observablecollection,我有以下定制的可观察的集合(代码部分取自Dean Chalk的博客,稍作修改): 除了wpf列表控件中的项的顺序与ViewModel的集合对象中的项的顺序相反之外,所有操作都非常正常 对于语句Collection.Insert(0,intem),我希望将新项添加到列表的顶部,但得到的结果与使用Collection.add(item)得到的结果相同 当我在运行时进入代码时,我可以验证我的集合中的项目的顺序是否正确,但在wpf列表控制的表面上,顺序被改变,即颠倒 我做错了什么 我猜问题一定是在数据绑

我有以下定制的可观察的集合(代码部分取自Dean Chalk的博客,稍作修改):

除了wpf列表控件中的项的顺序与ViewModel的集合对象中的项的顺序相反之外,所有操作都非常正常

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

当我在运行时进入代码时,我可以验证我的集合中的项目的顺序是否正确,但在wpf列表控制的表面上,顺序被改变,即颠倒

我做错了什么

我猜问题一定是在数据绑定的某个地方发现的,因为是“连线”将我的ObservableCollection与wpf控件连接起来,而且似乎一个正确的顺序进入连线,一个不正确的顺序离开连线

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

我没有线索,我真的被卡住了


提前感谢您提供的任何帮助…

您可以尝试这样做:

CollectionChanged(这是新的notifycollectionchangedentargs(NotifyCollectionChangedAction.Add,new List(){item},0));

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

关于您的代码的几个注释:

  • 命名:ThreadSafe,而不是ThreadSave
  • 竞争条件:您正在获取一个要调用的锁。GetEnumerator。然后释放锁,并返回该枚举数。这是不安全的,如果线程条件正确,将在运行时引发异常。这里应该做的是在锁定状态下创建列表的副本,然后向该副本返回枚举数
  • ReaderWriterLock存在一些已知的性能、可伸缩性和易出错的使用(例如重新进入)问题。改用
  • 这里的全部思想是将所有操作封送到UI线程。如果所有事情都发生在UI线程上,那么根本不需要任何锁定

最后,与其重新发明轮子,我建议使用一个现有的。

你是我绝对的英雄!!你的建议非常有效!!你真的救了我一天!!:)哦,我忘了说:非常感谢你鞠躬:)@Marc很乐意帮忙:)也请阅读《犹大邮报》。非常感谢你的提示。我在使用GetEnumerator()方法查看竞争条件时遇到问题:当我锁定该方法的开头时,其他线程在进入之前都必须等待,对吗?那么比赛在哪里?关于ReaderWriteLock类的使用,这是我第一次使用它,我没有使用它的经验-因此非常感谢您的提示,我将深入探讨这个主题:)RGERGERADING编组:我在多线程应用程序中使用这个类,其中集合由多个线程(UI线程除外)更改。。。关于方向盘:我使用了迪恩·查克的代码,并对其进行了一些修改->学分直接转到迪恩·查克,很抱歉我忘了提到这一点。我已经更新了上面我的第一篇文章。马克,其他的帖子读过这个集合了吗,还是只是写信给它?因为写入操作已经通过Dispatcher进行,因此,除非其他线程也在读取,否则没有理由使用锁。如果确实需要锁,则GetEnumerator会被破坏:是的,您正在锁定对枚举器的访问,但枚举器正在同一集合上操作,它可以在不同的线程上读写。下面是一个中断的场景:您的列表包含1项。线程调用.GetEnumerator。线程A调用enumerator.MoveNext(),该函数返回true以指示有可用项。线程B删除该项。线程调用list.CurrentItem,期望它是非null的,但实际上它是null的,因为另一个线程删除了它。现在我明白了:)我会重新考虑-现在我已经删除了获取和释放GetEnumerator()中的锁方法,我已将我的类重命名为ExtendedObservableCollection,以避免任何进一步的误导性命名和键入;)。。。非常感谢你的帮助
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

}
public class ViewModel {

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

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

    public void Insert (string item) {

        Collection.Insert(0, item);
    }

}
wpfContainer.LogList.ItemsSource = viewModel.Collection;
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<object>() { item }, 0));