async/await 继续太快了
async/await continuing too soon
所以我基本上是在尝试将过滤器进程的调用延迟 1.5 秒,以允许用户在需要时键入多个击键。如果键入新的击键,先前等待的任务将被取消并开始等待新的任务:
System.Threading.CancellationTokenSource token = new System.Threading.CancellationTokenSource();
private async void MyTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
token.Cancel();
await System.Threading.Tasks.Task.Delay(1500, token.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//Earlier I had tried this variant too:
//System.Threading.Tasks.Task.Delay(500, token.Token).ContinueWith(_ =>
//{
// this.filterText = (sender as TextBox).Text;
// (this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//});
}
但是过滤过程(View.Refresh()
行)在第一次击键时立即命中,无需等待。我的印象是,在令牌上调用 Cancel
会杀死 Delay()
,从而也会杀死继续任务,然后再植入下一个任务,但显然这个方案不起作用。
我错过了什么?
如果这对任何人有帮助,那么以下内容对我来说是正确的。我的错误是我错误地认为 CancellationTokenSource 是一个信号设备,可以多次使用。显然不是这样:
private System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource();
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
cts = new System.Threading.CancellationTokenSource();
try
{
await System.Threading.Tasks.Task.Delay(1500, cts.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(System.Threading.Tasks.TaskCanceledException ee)
{
}
}
张贴在这里作为我自己的记录,只是为了让其他人检查我仍然没有做错任何事情。
处理此问题的正确方法不是使用 Task.Delay
和例外(因为例外是针对特殊情况),而是使用 Timer
和 Timer.Elapsed
事件。
例如
using Timer = System.Windows.Forms.Timer;
private readonly Timer timer = new Timer();
private static string newText = "";
public Form1()
{
timer.Interval = 1500;
timer.Tick += OnTimedEvent;
}
private void MyTextBox_TextChanged(object sender, EventArgs e)
{
timer.Stop(); // sets the time back to 0
newText = (sender as TextBox).Text; // sets new text
timer.Start(); // restarts the timer
}
private void OnTimedEvent(Object source, EventArgs e)
{
filterText = newText;
(Resources["CVS"] as CollectionViewSource).View.Refresh();
}
(不确定这是否 100% 正确,但您明白了要点。)
与评论中的讨论相关的旧片段。
正如 post 所说:这不是必需的,因为 Task.Delay
将 link 成为 CancellationToken
的侦听器,因此 .Cancel()
将阻塞直到所有的听众都听到了。
using System.Threading;
using System.Threading.Tasks;
private CancellationTokenSource cts = new CancellationTokenSource();
private Task delayTask;
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
if (delayTask != null) {
try{await delayTask;}
catch(TaskCanceledException){}
}
cts = new CancellationTokenSource();
try
{
delayTask = Task.Delay(1500, cts.Token);
await delayTask;
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(TaskCanceledException)
{
}
}
所以我基本上是在尝试将过滤器进程的调用延迟 1.5 秒,以允许用户在需要时键入多个击键。如果键入新的击键,先前等待的任务将被取消并开始等待新的任务:
System.Threading.CancellationTokenSource token = new System.Threading.CancellationTokenSource();
private async void MyTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
token.Cancel();
await System.Threading.Tasks.Task.Delay(1500, token.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//Earlier I had tried this variant too:
//System.Threading.Tasks.Task.Delay(500, token.Token).ContinueWith(_ =>
//{
// this.filterText = (sender as TextBox).Text;
// (this.Resources["CVS"] as CollectionViewSource).View.Refresh();
//});
}
但是过滤过程(View.Refresh()
行)在第一次击键时立即命中,无需等待。我的印象是,在令牌上调用 Cancel
会杀死 Delay()
,从而也会杀死继续任务,然后再植入下一个任务,但显然这个方案不起作用。
我错过了什么?
如果这对任何人有帮助,那么以下内容对我来说是正确的。我的错误是我错误地认为 CancellationTokenSource 是一个信号设备,可以多次使用。显然不是这样:
private System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource();
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
cts = new System.Threading.CancellationTokenSource();
try
{
await System.Threading.Tasks.Task.Delay(1500, cts.Token);
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(System.Threading.Tasks.TaskCanceledException ee)
{
}
}
张贴在这里作为我自己的记录,只是为了让其他人检查我仍然没有做错任何事情。
处理此问题的正确方法不是使用 Task.Delay
和例外(因为例外是针对特殊情况),而是使用 Timer
和 Timer.Elapsed
事件。
例如
using Timer = System.Windows.Forms.Timer;
private readonly Timer timer = new Timer();
private static string newText = "";
public Form1()
{
timer.Interval = 1500;
timer.Tick += OnTimedEvent;
}
private void MyTextBox_TextChanged(object sender, EventArgs e)
{
timer.Stop(); // sets the time back to 0
newText = (sender as TextBox).Text; // sets new text
timer.Start(); // restarts the timer
}
private void OnTimedEvent(Object source, EventArgs e)
{
filterText = newText;
(Resources["CVS"] as CollectionViewSource).View.Refresh();
}
(不确定这是否 100% 正确,但您明白了要点。)
与评论中的讨论相关的旧片段。
正如 post 所说:这不是必需的,因为 Task.Delay
将 link 成为 CancellationToken
的侦听器,因此 .Cancel()
将阻塞直到所有的听众都听到了。
using System.Threading;
using System.Threading.Tasks;
private CancellationTokenSource cts = new CancellationTokenSource();
private Task delayTask;
private async void TenantsFilter_TextChanged(object sender, TextChangedEventArgs e)
{
cts.Cancel();
if (delayTask != null) {
try{await delayTask;}
catch(TaskCanceledException){}
}
cts = new CancellationTokenSource();
try
{
delayTask = Task.Delay(1500, cts.Token);
await delayTask;
this.filterText = (sender as TextBox).Text;
(this.Resources["CVS"] as CollectionViewSource).View.Refresh();
}
catch(TaskCanceledException)
{
}
}