为什么RadListBox需要调度员?
为什么RadListBox需要调度员?
我有一个DataGrid,它通过异步方法从ViewModel中加载数据。我的DataGrid如下所示:\n
\n我正在使用http://www.amazedsaint.com/2010/10/asynchronous-delegate-command-for-your.html来在我的视图模型中实现异步方式。\n以下是我的视图模型代码:\n
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); } }
\n正如您在我的ViewModel中的Load()方法中看到的,首先我从服务中获取matchList(一个DataContract类的列表)。然后通过foreach循环将matchList的项插入到_matchObsCollection(一个DataContract类的ObservableCollection)中。现在我在这里遇到了上述错误(如我在标题中所示)“这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection”。 \n\n有人能给我提供任何解决方案吗?此外,如果可能的话,我想知道如何在视图中绑定我的DataGrid,并在异步地刷新它时是否有更好的方法。
为什么RadListBox需要使用Dispatcher?
在WPF应用程序中,当涉及到多线程操作时,需要使用Dispatcher来处理UI元素的更新。UI元素只能在创建它们的线程上进行访问和更新,如果在其他线程上尝试更新UI元素,会导致线程间的冲突和异常。
解决方法有以下几种:
1. 使用App.Current.Dispatcher.Invoke方法:
App.Current.Dispatcher.Invoke((System.Action)delegate { _matchObsCollection.Add(match); });
这种方法会将更新UI元素的操作委托给创建UI元素的线程,确保在正确的线程上进行更新。
2. 使用SynchronizationContext.Send方法:
var uiContext = SynchronizationContext.Current; uiContext.Send(x => _matchObsCollection.Add(match), null);
这种方法将责任交给发布者,要求他们在正确的线程上调用或调用操作,通过SynchronizationContext.Send方法更新UI元素。
3. 使用CollectionSynchronization来管理线程同步:
private static object _lock = new object(); public MainWindowViewModel() { _matchObsCollection = new ObservableCollection(); BindingOperations.EnableCollectionSynchronization(_matchObsCollection, _lock); }
通过调用BindingOperations.EnableCollectionSynchronization方法,可以启用集合的线程同步。这样,无论在哪个线程上进行调用,都不需要担心线程问题,责任不再由发布者承担。
以上是解决RadListBox需要使用Dispatcher的方法,通过正确的线程处理UI元素的更新,可以避免线程冲突和异常的发生。在调试过程中,可以使用Visual Studio的Threads窗口查看当前线程的信息。
为什么RadListBox需要调度程序?
在WPF 4.5中,你应该可以毫无问题地做到这一点。然而,要解决这个问题,你应该使用同步上下文。在启动线程之前,你必须在UI线程中存储同步上下文。
var uiContext = SynchronizationContext.Current;
然后在你的线程中使用它:
uiContext.Send(x => _matchObsCollection.Add(match), null);
请参考这个教程:[Understanding SynchronizationContext Part I](http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I)
谢谢你的迅速回复。我尝试了`uiContext.Send(() => _matchObsCollection.Add(match), null);`,但是它给出了语法错误。看起来`Send`方法需要一个回调方法名称。我尝试了各种选项,如带参数的委托,但是它不允许我使用自定义参数。我对这种语法非常陌生,如果你能提供调用这个方法的语法,那就太好了。
抱歉,我犯了一个错误,我已经更正了。应该是`uiContext.Send(x => _matchObsCollection.Add(match), null);`
我收到了一个毫无意义的错误。我不知道它在说什么。System.Windows.Markup.XamlParseException: 'Must create DependencySource on same Thread as the DependencyObject.'
为了解决这个问题,你需要使用调度程序来确保在UI线程上执行操作。在添加元素到_matchObsCollection集合时,你需要使用调度程序来确保在UI线程上执行。
这就是为什么需要调度程序的原因以及解决方法。
为什么RadListBox需要调度程序?
在RadListBox中,如果你的ObservableCollection是在UI线程上创建的,那么你只能在UI线程上修改它,而不能在其他线程上修改。这被称为“线程亲和性”。
如果你需要从不同的线程更新在UI线程上创建的对象,只需将委托放在UI调度程序上,它会将工作委托给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); }); } }
还可以使用以下代码:
Application.Current.Dispatcher.BeginInvoke((Action)(() => { matchList = new List(); matchList = proxy.GetMatch().ToList(); foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList) { _matchObsCollection.Add(match); } }));
`BeginInvoke`将异步更新集合。所以,如果你想以这种方式更新,那么这样做也可以。希望对你有帮助。
或者你可以使用这个:codeproject.com/Articles/64936/…
感谢这个答案。我之前使用的是Dispatcher.Current.Invoke,这给我带来了麻烦,但是使用App.Current.Dispatcher可以工作正常。显然它们是不同的!
这个调用应该在foreach之外。如果你添加了数百个项目,你会饱和调度程序队列,并为用户引入UI延迟。