CollectionView 不支持在等待后从与 Dispatcher 线程不同的线程更改其 SourceCollection

问题描述 投票:0回答:1

我有一个带有 ICommand 的 WPF 应用程序,如下所示:

public ObservableCollection<Consultant> Consultants { get; set; }

public Consultant Selected { get; set; }

public ICommand InsertCommand => this.insertCommand ?? (this.insertCommand = new RelayCommand(async () =>
{
    string result = await InsertAsync(this.Selected.Name, this.Selected.ID);

    if (string.IsNullOrEmpty(result))
    {
        this.Consultants.Remove(this.Consultants.Single(i => i == this.Selected));
    }
    else if (!string.IsNullOrEmpty(result))
    {
        this.dialogService.ShowMessage(result, "Add Consultant");
    }
}));

问题是

this.Consultants.Remove(this.Consultants.Single(i => i == this.Selected));
行抛出异常
CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread

我感到困惑的是,即使我取出所有其他代码(即之前的

await
行),它仍然会抛出此错误。为什么在这种情况下运行不同的线程(即非 UI/主线程)?

我不记得必须对其他类似命令执行此操作,但也许我从

Consultants
中删除记录的方式不同,从而导致了问题。

我可以将该行放在

Dispatcher.Invoke
中,但我担心这掩盖了我的代码/逻辑中的另一个问题。

c# wpf
1个回答
0
投票

我找到了问题的根本原因。在我的

LoadData
方法中,集合
this.Consultants
是从
Task.Run
设置的,如下所示:

Task tsk = Task.Run(() =>
{
    return this.GetConsultantsAsync(false);
}).ContinueWith(t =>
{
    if (t.IsCompleted)
    {
        this.Consultants = t.Result;
    }
});

这意味着该集合是在线程池线程上设置的,而不是在主线程上设置的,正如我所预期的那样,这随后发生在我的

InsertCommand
中。所以我保留了
InsertCommand
,而是将加载方法更改为:

Task tsk = Task.Run(() =>
{
    return this.GetConsultantsAsync(false);
}).ContinueWith(t =>
{
    if (t.IsCompleted)
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            this.Consultants = t.Result;
        });
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.