C# 访问包含多线程ObservableCollections的CollectionViewSource中的第一项

C# 访问包含多线程ObservableCollections的CollectionViewSource中的第一项,c#,wpf,multithreading,sorting,collectionviewsource,C#,Wpf,Multithreading,Sorting,Collectionviewsource,作为我尝试修复的一部分,我尝试只更新绑定的ObservableCollection,而不是每隔几秒钟就替换整个集合。显然,它给出了一个错误,因为事件无法修改它。因此,我创建了一个基于 当然,这意味着只对视图进行排序,而不对集合本身进行排序。我需要在第一个位置结束的ViewModel的数据。大按钮(如另一期所示)必须反映第一个位置的数据。包含所有业务代码的选项卡管理器只能访问宿主窗体和主视图模型。它不能直接与承载列表的选项卡控件一起工作。这些就是我尝试过的 根据创建FirstInView扩展名。我

作为我尝试修复的一部分,我尝试只更新绑定的ObservableCollection,而不是每隔几秒钟就替换整个集合。显然,它给出了一个错误,因为事件无法修改它。因此,我创建了一个基于

当然,这意味着只对视图进行排序,而不对集合本身进行排序。我需要在第一个位置结束的ViewModel的数据。大按钮(如另一期所示)必须反映第一个位置的数据。包含所有业务代码的选项卡管理器只能访问宿主窗体和主视图模型。它不能直接与承载列表的选项卡控件一起工作。这些就是我尝试过的

  • 根据创建
    FirstInView
    扩展名。我通过调用MyCollectionProperty.FirstInView()尝试在父视图模型以及选项卡管理器中使用它
  • 尝试使用中的示例访问它
  • 试图使用另一篇文章中提到的
  • 查看了,但认为没有帮助,因为可以添加、删除或更新项目,使它们每隔几秒钟在视图中移动一次
  • 在CollectionViewSource中检索第一个ViewModel的所有尝试都以一件事结束:应用程序将无误关闭。我不知道这是因为我试图在mulithreaded集合上执行这些任务,还是因为其他原因

    无论哪种方式,我都不知道如何从排序视图中获取顶部项。在我使用CollectionViewSource之前,我通过编程对它进行排序并构建一个新列表,这样我就可以获取第一个列表。这是不可能的,因为我正在更新而不是重建

    除了我复制收藏、排序、存储第一个ViewModel,然后丢弃排序后的副本之外,你还有其他想法吗

    编辑1 我再次尝试了1和2。对于这两种情况,在将第二个项目添加到集合后获取视图时都会发生错误,但在仅添加第一个项目后,该错误似乎可以正常工作。这与我试图更新常规ObservableCollection项时发生的错误非常相似(并导致我使用多线程版本)

    仍然为空。它显示零项,因此
    moved
    为false,
    col.Current
    失败

    编辑3 看起来我不得不依靠手动对集合进行排序,而不使用
    CollectionViewSource

    IEnumerable<DepthLevelViewModel> depthQuery = ((MyBaseViewModel)this.DataContext).AskDepthAsync.OrderBy(d => d.QuotePriceDouble);
    List<DepthLevelViewModel> depthList = depthQuery.ToList<DepthLevelViewModel>();
    DepthLevelViewModel item = depthList[0];
    ((MyBaseViewModel)this.DataContext).AskDepthCurrent = item;
    
    IEnumerable depthQuery=((MyBaseViewModel)this.DataContext).AskDepthAsync.OrderBy(d=>d.QuotePriceDouble);
    List depthList=depthQuery.ToList();
    DepthLevelViewModel项=depthList[0];
    ((MyBaseViewModel)this.DataContext).AskDepthCurrent=item;
    
    因为这不是一个理想的方法,所以我不回答这个问题。但是,在找到永久解决方案之前,这已经足够了

    编辑4
    我已将解决方案迁移到VS2015,并将每个项目的框架升级到4.6。因此,如果你知道一些新的方法可以奏效,我很乐意听你这么说。

    这可能不是最理想的方法,但这是我所做的唯一比重新排序更有效的方法

    在定义了
    CollectionViewSource
    的选项卡内容控件(视图)和跨功能(各种视图、选项卡管理器等)使用的父级
    DataContext
    中,我添加了以下内容:

      void TabItemControl_DataContextChanged(object sender,
         DependencyPropertyChangedEventArgs e)
      {
         ((TabViewModel)DataContext).AskCollection = (CollectionViewSource)Resources["AskDepthCollection"];
         ((TabViewModel)DataContext).BidCollection = (CollectionViewSource)Resources["BidDepthCollection"];
      }
    
    这将存储对选项卡上使用的已排序集合的引用。在选项卡管理器中,我将:

      Private Function GetFirstQuote(ByVal eType As BridgeTraderBuyIndicator) As DepthLevelViewModel
    
         Dim cView As ICollectionView
         Dim cSource As CollectionViewSource
         Dim retView As DepthLevelViewModel = Nothing
    
         If eType = BridgeTraderBuyIndicator.Buy Then
            cSource = multilegViewModel.AskCollection
         Else
            cSource = multilegViewModel.BidCollection
         End If
    
         Try
            cView = cSource.View()
    
            Dim enumerator As IEnumerator = cView.Cast(Of DepthLevelViewModel).GetEnumerator()
            Dim moved As Boolean = enumerator.MoveNext()
            If moved Then
               retView = DirectCast(enumerator.Current(), DepthLevelViewModel)
            Else
               ApplicationModel.Logger.WriteToLog((New StackFrame(0).GetMethod().Name) & ": ERROR - Unable to retrieve the first quote.", LoggerConstants.LogLevel.Heavy)
            End If
         Catch ex As Exception
            ApplicationModel.AppMsgBox.DebugMsg(ex, (New StackFrame(0).GetMethod().Name))
         End Try
    
         Return retView
    
      End Function
    
    当我需要得到第一件物品时,我只是这样称呼它:

            Dim ask As DepthLevelViewModel
            ask = GetFirstQuote(MyTypeEnum.Buy)
    

    如果没有更好的解决方案,我会将此项标记为已接受的答案。

    如果有一个事件/触发器可以应用于列表,让它知道内容已更改,并且有一种方法可以从集合视图中显示第一项,我也可以使用它。我可以在tab控件中编写代码,将俯视图指定给新属性,并将大按钮绑定到该属性。我只是需要一些东西在这方面取得一些进展。我在更新常规ObservableCollection时遇到的问题是,当尝试使用
    FirstInView
    扩展名时,MTObservableCollection发生了什么情况:
    Error:[Error.initialization.failed]NotSupportedException,这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection。
    此时,我不确定如何绕过它。但是,我将继续努力,直到我不得不求助于排序和抛出hack。我用第二种方法再次尝试,它给出了与第一种方法相同的错误。但是,我在试图从中检索第一个视图模型的“属性”中添加了日志记录。显然,当集合中添加了第一个项时,它可以正常工作,但当将另一个项添加到集合中并再次调用代码时,它会给出错误。这似乎与第一个原因相同,因为它在获取视图时爆炸:
    CollectionViewSource.GetDefaultView(AskDepthAsync)
     this.Dispatcher.Invoke(DispatcherPriority.Normal, new DispatcherOperationCallback(delegate
     {
        //ICollectionView view = CollectionViewSource.GetDefaultView(((MyBaseViewModel)this.DataContext).AskDepthAsync);
        ICollectionView view = CollectionViewSource.GetDefaultView(this.askDepthList.ItemsSource);
        IEnumerable<DepthLevelViewModel> col = view.Cast<DepthLevelViewModel>();
        List<DepthLevelViewModel> list = col.ToList();
        ((MyBaseViewModel)this.DataContext).AskDepthCurrent = list[0];
        return null;
     }), null);
    
    ICollectionView view = CollectionViewSource.GetDefaultView(this.askDepthList.ItemsSource);
    var col = view.GetEnumerator();
    bool moved = col.MoveNext();
    DepthLevelViewModel item = (DepthLevelViewModel)col.Current;
    ((MyBaseViewModel)this.DataContext).AskDepthCurrent = item;
    
    IEnumerable<DepthLevelViewModel> depthQuery = ((MyBaseViewModel)this.DataContext).AskDepthAsync.OrderBy(d => d.QuotePriceDouble);
    List<DepthLevelViewModel> depthList = depthQuery.ToList<DepthLevelViewModel>();
    DepthLevelViewModel item = depthList[0];
    ((MyBaseViewModel)this.DataContext).AskDepthCurrent = item;
    
      void TabItemControl_DataContextChanged(object sender,
         DependencyPropertyChangedEventArgs e)
      {
         ((TabViewModel)DataContext).AskCollection = (CollectionViewSource)Resources["AskDepthCollection"];
         ((TabViewModel)DataContext).BidCollection = (CollectionViewSource)Resources["BidDepthCollection"];
      }
    
      Private Function GetFirstQuote(ByVal eType As BridgeTraderBuyIndicator) As DepthLevelViewModel
    
         Dim cView As ICollectionView
         Dim cSource As CollectionViewSource
         Dim retView As DepthLevelViewModel = Nothing
    
         If eType = BridgeTraderBuyIndicator.Buy Then
            cSource = multilegViewModel.AskCollection
         Else
            cSource = multilegViewModel.BidCollection
         End If
    
         Try
            cView = cSource.View()
    
            Dim enumerator As IEnumerator = cView.Cast(Of DepthLevelViewModel).GetEnumerator()
            Dim moved As Boolean = enumerator.MoveNext()
            If moved Then
               retView = DirectCast(enumerator.Current(), DepthLevelViewModel)
            Else
               ApplicationModel.Logger.WriteToLog((New StackFrame(0).GetMethod().Name) & ": ERROR - Unable to retrieve the first quote.", LoggerConstants.LogLevel.Heavy)
            End If
         Catch ex As Exception
            ApplicationModel.AppMsgBox.DebugMsg(ex, (New StackFrame(0).GetMethod().Name))
         End Try
    
         Return retView
    
      End Function
    
            Dim ask As DepthLevelViewModel
            ask = GetFirstQuote(MyTypeEnum.Buy)