为什么RadListBox需要调度员?

13 浏览
0 Comments

为什么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\"enter\n有人能给我提供任何解决方案吗?此外,如果可能的话,我想知道如何在视图中绑定我的DataGrid,并在异步地刷新它时是否有更好的方法。

0
0 Comments

为什么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窗口查看当前线程的信息。

0
0 Comments

为什么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线程上执行。

这就是为什么需要调度程序的原因以及解决方法。

0
0 Comments

为什么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延迟。

0