如何在C#中创建可重新触发的延迟?
我有一个用户名的字符串属性,通过MVVM连接到一个文本条目,每当设置它时,我调用一个方法来检查服务器,看看用户名是否可用。现在我不希望每次键入一个键时都调用它,而是希望它能够检测用户何时停止键入 目前这是我的代码如何在C#中创建可重新触发的延迟?,c#,asynchronous,task,delay,C#,Asynchronous,Task,Delay,我有一个用户名的字符串属性,通过MVVM连接到一个文本条目,每当设置它时,我调用一个方法来检查服务器,看看用户名是否可用。现在我不希望每次键入一个键时都调用它,而是希望它能够检测用户何时停止键入 目前这是我的代码 private string _username; public string Username { get => _username; set { SetProperty(ref _username, value); Ta
private string _username;
public string Username
{
get => _username;
set
{
SetProperty(ref _username, value);
Task.Run(async () => await CheckUsernameExists(1000));
}
}
然后CheckUsernameExists()方法
/// <summary>
/// Checks if the username already exists
/// </summary>
/// <returns></returns>
public async Task CheckUsernameExists(int timeoutInMilliseconds)
{
await Task.Delay(timeoutInMilliseconds);
try
{...
//
///检查用户名是否已存在
///
///
公共异步任务CheckUsernameExists(int-timeoutin毫秒)
{
等待任务。延迟(timeoutin毫秒);
尝试
{...
但是,这不会重新触发它,它只是将呼叫延迟1秒
我从虚幻的引擎4中得到了一个可触发延迟的想法
UE4 one的情况是,函数被调用一次。然后它在可触发延迟上启动计时器。如果在计时器运行时再次调用该函数,它将重新启动计时器。然后,只有当它完成时,才会在它之后调用代码
有人知道如何在C#中执行此操作吗?谢谢!以下是对每种类型开始延迟检查的代码,但只有最后一次调用才真正检查用户名:
private int _checkUsernameCalls = 0;
public string Username
{
get => _username;
set
{
SetProperty(ref _username, value);
_checkUsernameCalls++;
Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(t => CheckUsernameExists());
}
}
void CheckUsernameExists()
{
if (--_checkUsernameCalls > 0)
{
return;
}
// actual checks...
}
…我想让它检测用户何时停止键入
要调用只在用户停止键入后才检查服务器的函数,实际上这是一个非常简单的逻辑。只要用户在控件中键入字符(比如文本框),就可以启动System.Timers.Timer
,这样做。将计时器设置为在计时器达到时触发已用
事件,例如150毫秒。最后,您可以订阅已用
事件,并在服务器上分配发出请求的功能。每当用户向文本框输入新输入时,计时器将重置,您将获得所需的行为(因为只有当计时器达到您设置的延迟时才会触发已用事件)。要执行此操作,请使用CancellationTokenSource
对象。在取消前一个对象后,每次属性更改时都创建一个新的对象
private string _username;
public string Username
{
get => _username;
set
{
SetProperty(ref _username, value);
CheckUsernameExistsAsync(value, 1000);
}
}
private CancellationTokenSource _cts;
private async void CheckUsernameExistsAsync(string username, int timeout)
{
try
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
var cancellationToken = _cts.Token;
await Task.Delay(timeout, cancellationToken);
// Check if the username exists
// Use the same cancellationToken if the API supports it
}
catch (TaskCanceledException)
{
// Ignore the exception
}
catch (Exception)
{
// Log the exception
}
}
警告:类CancellationTokenSource
是一次性的,但我没有在上面的示例中处理它。我不确定这是否是一个大问题。可能不是。这里有一个相关的问题:这是WPF中的吗?如果是,是什么版本?注意:
您可能需要使用Lock()在访问_checkUsernameCalls变量(或使其成为线程安全属性)时,因为它将是多线程环境。