首页 > 解决方案 > 有没有一种可靠的方法可以在不使用 Cancel 的情况下停止线程?

问题描述

我的情况似乎与大多数人的需要相反。我不需要阻塞线程,我也没有看到“合作取消”这件事的好方法。

我有UserControl一个网格控件。该网格的选择用于通知同一UserControl. 当用户选择行时,会async获取相关记录。有时,该提取所需的时间比用户选择不同行所需的时间长,从而导致该新行的线程提取。当用户在网格中从一行移动到另一行时,这会重复。例如,他们可以使用箭头键,这样他们就可以快速地逐行移动。

我无法阻止线程,因为我需要获取当前选定行的数据。相反,我需要一种有效的方法来立即停止之前的尝试。否则,这些获取会堆积起来,有时我什至会OutOfMemoryExceptions发现相关数据足够大。

这是基本思想和示例:

用户单击网格行,bound 属性会触发一个获取详细数据的方法,该方法包括对相关项目的 fetch 调用:

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()方法中唯一真正起作用的行是从数据库中获取数据,因此没有好地方可以查找 Cancel 标志。

我想知道我使用公共集合作为这些返回记录集的最终目的地是否是问题的一部分?

标签: c#wpfasync-await

解决方案


没有办法“立即停止”和不支持立即停止或取消的操作。你的GetDataList()方法不行。一旦它被调用,它将一直运行,直到它完成或抛出异常。

此外,属性设置器不应启动异步操作:https ://blog.stephencleary.com/2013/01/async-oop-3-properties.html

您可以在这里做的是处理PropertyChanged该属性的事件SelectedRecord,取消当前正在执行的任何任务并启动另一个任务。

任务完成后,您需要确定结果是否仍然准确,或者自任务开始后是否做出了新的选择。如果是后者,您可以丢弃结果并等待最后一个结果。

处理这个问题的另一个选择是使用像ReactiveUI这样支持响应式和可组合属性的库。


推荐阅读