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