我有一个 DataGrid,它通过异步方法从 ViewModel 填充数据。我的 DataGrid 是:
<DataGrid ItemsSource="{Binding MatchObsCollection}" x:Name="dataGridParent" Style="{StaticResource EfesDataGridStyle}" HorizontalGridLinesBrush="#DADADA" VerticalGridLinesBrush="#DADADA" Cursor="Hand" AutoGenerateColumns="False" RowDetailsVisibilityMode="Visible" >
我正在使用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<EfesBet.DataContract.GetMatchDetailsDC>(); } List<EfesBet.DataContract.GetMatchDetailsDC> matchList; ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> _matchObsCollection; public ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> MatchObsCollection { get { return _matchObsCollection; } set { _matchObsCollection = value; OnPropertyChanged("MatchObsCollection"); } } // public void Load() { matchList = new List<GetMatchDetailsDC>(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { _matchObsCollection.Add(match); } }
正如您在 ViewModel 中的 Load() 方法中看到的,首先我从服务中获取 matchList(这是 DataContract 类的列表)。然后通过 foreach 循环,我将 matchList 项插入到我的 _matchObsCollection(这是一个 ObservableCollection DataContract 类))。现在我收到上述错误(如标题中所示)“这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection”
谁能建议我任何解决方案。此外,如果可能的话,我想知道如何在 View 中绑定我的 DataGrid,如果有更好的方法,也可以异步刷新它。
由于您的 ObservableCollection 是在 UI 线程上创建的,因此您只能从 UI 线程修改它,而不能从其他线程修改它。这称为线程亲和性。
如果您需要从不同的线程更新在 UI 线程上创建的对象,只需put the delegate on UI Dispatcher将其委派给 UI 线程即可。这将起作用 -
put the delegate on UI Dispatcher
public void Load() { matchList = new List<GetMatchDetailsDC>(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE { _matchObsCollection.Add(match); }); } }