当TextBox文本更改时取消异步任务,然后重新启动它



我有.NET应用程序,GUI上有DataGridView和TextBox。我想做的是,当用户更改TextBox文本时,更新单元格中包含此文本的DataGridView。但这个搜索应该作为异步任务运行,因为如果不是,它会导致GUI冻结。每次用户更改TextBox文本时,如果另一个搜索任务正在运行,我的应用程序都应该取消,并重新运行它以根据新的搜索值进行搜索。这是我的密码;

CancellationTokenSource cts = new CancellationTokenSource();
private async void TextBox1_Changed(object sender, EventArgs e)    
{
cts.Cancel();
CancellationToken ct = cts.Token;
try
{
await Task.Run(() =>
{
System.Diagnostics.Debug.WriteLine("Task started");
// Searching here.
System.Diagnostics.Debug.WriteLine("Task finished");
}, cts.Token);
}
catch
{
System.Diagnostics.Debug.WriteLine("Cancelled");
}
}

在我的代码中,任务在没有启动的情况下被取消。我只看到";取消";调试控制台上的行。我应该取消任务,因为如果我不取消,它们的数量和应用程序的CPU使用量就会增加。有办法做到这一点吗?

就像Rand Random所说的,我应该对new CancellationTokenSource对象进行declear。我已经像这样编辑了我的代码,它很有效。代码应该是这样的:

CancellationTokenSource cts = new CancellationTokenSource();
private async void TextBox1_Changed(object sender, EventArgs e)    
{
cts.Cancel();
cts.Dispose();
cts = new CancellationTokenSource();
try
{
await Task.Run(() =>
{
System.Diagnostics.Debug.WriteLine("Task started");
// Searching here.
System.Diagnostics.Debug.WriteLine("Task finished");
}, cts.Token);
}
catch
{
System.Diagnostics.Debug.WriteLine("Cancelled");
}
}

如果你想让自己的生活变得轻松,你应该考虑使用微软的反应式框架(又名Rx(

我假设你可以写这个方法:

async Task<string[]> DoSearchAsync(string text, CancellationToken ct)
{
/* you implement this method */
}

然后你可以这样做:

private IDisposable _searchSubscription = null;
private void Form1_Load(object sender, EventArgs e)
{
_searchSubscription =
Observable
.FromEventPattern(h => TextBox1.TextChanged += h, h => TextBox1.TextChanged -= h)
.Throttle(TimeSpan.FromMilliseconds(400.0))
.Select(ep => TextBox1.Text)
.Select(text => Observable.FromAsync(ct => DoSearchAsync(text, ct)))
.Switch()
.ObserveOn(TextBox1)
.Subscribe(results => { /* update your UI */ });
}

现在,它监视你的TextChanged事件,等待400.0毫秒,以防你键入另一个字符——如果用户仍在键入,那么启动大量搜索是没有意义的——然后它调用你的新DoSearchAsync方法。

然后它执行Switch,这实际上意味着取消任何飞行中的搜索并开始新的搜索。

最后,它整理回UI线程,然后向您提供搜索结果,以便您可以更新UI。

它只处理所有的调用、后台线程调用、编组回UI,所有这些都是为您准备的。

如果您想关闭它,只需调用_searchSubscription.Dispose()即可。

NuGetSystem.Reactive.Windows.Forms并加上CCD_。

最新更新