这种类型的CollectionView不支持从与调度程序线程不同的线程更改其SourceCollection
这种类型的CollectionView不支持从与调度程序线程不同的线程更改其SourceCollection
这个问题已经在此处有答案:
我有一个DataGrid,它通过异步方法从ViewModel中填充数据。我的DataGrid是:
我正在使用http://www.amazedsaint.com/2010/10/asynchronous-delegate-command-for-your.html实现视图模型中的异步方式。
这是我的视图模型代码:
public class MainWindowViewModel:WorkspaceViewModel,INotifyCollectionChanged { MatchBLL matchBLL = new MatchBLL(); EfesBetServiceReference.EfesBetClient proxy = new EfesBetClient(); public ICommand DoSomethingCommand { get; set; } public MainWindowViewModel() { DoSomethingCommand = new AsyncDelegateCommand( () => Load(), null, null, (ex) => Debug.WriteLine(ex.Message)); _matchObsCollection = new ObservableCollection(); } List matchList; ObservableCollection _matchObsCollection; public ObservableCollection MatchObsCollection { get { return _matchObsCollection; } set { _matchObsCollection = value; OnPropertyChanged("MatchObsCollection"); } } // public void Load() { matchList = new List(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { _matchObsCollection.Add(match); } }
正如您在我的ViewModel的Load()方法中所看到的那样,我首先从服务中获取matchList(它是DataContract类的列表)。然后,通过foreach循环,我将我的matchList项插入到我的_matchObsCollection(它是DataContract类的ObservableCollection)中。现在,在这里,我正在遇到上面显示的错误(如标题所示)“此CollectionView类型不支持来自与Dispatcher线程不同的线程的SourceCollection更改”。
有人可以给我建议吗?此外,如果有可能,我想知道如何在View中绑定我的DataGrid并异步刷新它(如果有更好的方法)。
如果我没有记错,在WPF 4.5中,您应该可以毫无问题地完成这项工作。
现在,要解决这个问题,您应该使用同步上下文。在启动线程之前,您必须在UI线程中存储同步上下文。
var uiContext = SynchronizationContext.Current;
然后在您的线程中使用它:
uiContext.Send(x => _matchObsCollection.Add(match), null);
参考这个教程:http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I
由于你的ObservableCollection是在UI线程上创建的,你只能从UI线程修改它,而不能从其他线程修改。这被称为线程亲和性。
如果你需要从不同的线程更新在UI线程上创建的对象,只需将委托放在UI Dispatcher上
,它将委托给UI线程完成工作。这将起作用 –
public void Load() { matchList = new List(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE { _matchObsCollection.Add(match); }); } }