【发布时间】:2017-05-08 17:11:13
【问题描述】:
我有一个ObservableCollection<string> 绑定到 WPF 视图。有一种方法可以刷新集合的内容。此方法在后台线程中处理,需要几秒钟。为避免错误,调用的方法是同步的。
即使之前的处理尚未完成,也可能会调用该方法。在这种情况下,我想停止当前的处理并开始新的处理。
private ObservableCollection<string> col = new ObservableCollection<string>();
private async void Refresh()
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(() =>
{
return GetNewObjects();
}).ContinueWith(t =>
{
col = t.Result;
}, ui);
}
[MethodImpl(MethodImplOptions.Synchronized)]
private ObservableCollection<string> GetNewObjects()
{
// processing
}
我的想法是在 Refresh() 中保存相应 Task 的引用,并检查每个调用,如果已经有正在运行的任务。这是停止任务的正确(和安全)方式吗?
【问题讨论】:
-
您可能会尝试
CancellationToken。顺便说一句,为什么不Task.Run()?你还在使用 .NET 4.0 吗? -
老实说,不。我对.net 一点也不陌生。我正在寻找一种刷新视图的好方法,而不冻结 ui 线程。这是我的第一个工作方式。为什么使用 Task.Run()?有什么好处?
-
我认为这是不可能的。 UI 线程上的延续是一个致命的细节,总是会导致死锁。不是唯一的问题,GetNewObjects() 必须使用来自 UI 的 some 类型的数据来产生不同的结果。我们看不到它,但唯一有意义的事情。您不能允许该数据在执行时更改。
-
每次单击另一个 ObservableCollection 中的复选框时,都会调用 GetNewObjects()。每个选中的复选框都将成为 GetNewObjects() 方法的输入。实际上,“[MethodImpl(MethodImplOptions.Synchronized)]”会导致顺序处理。但这就是问题所在。当方法被调用 2 次时,有趣的结果是最后一次调用。每次调用后,之前的结果都不再相关。
-
Task.Run()是在 .NET 4.5+ 中启动任务的首选方法,请阅读 this answer 了解详细信息。
标签: c# wpf multithreading