我有一个带有 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
中,但我担心这掩盖了我的代码/逻辑中的另一个问题。
我找到了问题的根本原因。在我的
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;
});
}
});