【发布时间】:2019-10-25 19:23:26
【问题描述】:
我的情况似乎与大多数人的需要相反。我不需要阻塞线程,也没有看到“合作取消”这件事的好方法。
我有一个UserControl,上面有一个网格控件。该网格的选择用于通知同一UserControl 上的详细信息面板。当用户选择行时,会有一个async 获取相关记录。有时,该提取所需的时间比用户选择不同行所需的时间长,从而导致该新行的线程提取。当用户在网格中从一行移动到另一行时,这会重复。例如,他们可以使用箭头键,这样他们就可以快速地从一行移动到另一行。
我无法阻止线程,因为我需要获取当前选定行的数据。相反,我需要一种有效的方法来立即停止之前的尝试。否则,这些获取会堆积起来,如果相关数据足够大,我有时甚至会得到OutOfMemoryExceptions。
这是基本思想和示例:
用户单击网格行,绑定属性触发一个获取详细数据的方法,其中包括对相关项目的获取调用:
private ObservableCollection<DataRecord> _currentData = null;
public ObservableCollection<DataRecord> CurrentData
{
get => _currentData;
set => SetProperty(ref _currentData, value, () => CurrentData);
}
public DataRecord SelectedRecord
{
get => _selectedRecord;
set
{
SetProperty(ref _selectedRecord, value, () => SelectedRecord);
FetchDataAsync();
}
}
public async void FetchDataAsync()
{
CurrentData?.Clear();
var dataList = await System.Threading.Tasks.Task.Run(() => GetDataList());
CurrentData = dataList.ToObservableCollection();
}
private List<DataRecord> GetDataList()
{
var dataList = new List<DataRecord>();
using (var context = new DataContext(new DbFactory().GetConnectionString()))
dataList = context.MyDataTable.Where(x => x.ID == SelectedRecord.ID).ToList();
return dataList;
}
在GetDataList() 方法中真正起作用的唯一行是从数据库中获取数据,因此没有好地方可以查找取消标志。
我想知道我使用公共集合作为这些返回记录集的最终目的地是否是问题的一部分?
【问题讨论】:
-
使请求一直异步并传递
CancellationToken。当用户更改他们的选择时取消令牌。 -
可靠的方法是使用 CancellationToke。
async void不应该被使用,除了事件处理程序,这意味着FetchDataAsync有一个坏的错误。async void不能等待,运行时对这些任务一无所知,当它们运行时,它们尝试访问的对象可能已经被释放 -
停止使用 linq 的循环并自己制作,然后你有很多地方可以取消。每次迭代一次。
-
您使用的是什么 ORM? EF 有 ToListAsync 这意味着不需要 Task.Run 和
GetDataList()。您也不需要ToObservableCollection来设置属性并引发通知事件。ObservableCollection仅在您想要修改集合时需要 -
PS:WPF 有延迟绑定。也许您需要做的就是将
Delay添加到您的绑定中。检查Rick Strahl's article on Debouncing 其中还提到了Text="{Binding TopicsFilter,UpdateSourceTrigger=PropertyChanged,Delay=500}"
标签: c# wpf async-await