如何在C#中创建可重新触发的延迟?

如何在C#中创建可重新触发的延迟?,c#,asynchronous,task,delay,C#,Asynchronous,Task,Delay,我有一个用户名的字符串属性,通过MVVM连接到一个文本条目,每当设置它时,我调用一个方法来检查服务器,看看用户名是否可用。现在我不希望每次键入一个键时都调用它,而是希望它能够检测用户何时停止键入 目前这是我的代码 private string _username; public string Username { get => _username; set { SetProperty(ref _username, value); Ta

我有一个用户名的字符串属性,通过MVVM连接到一个文本条目,每当设置它时,我调用一个方法来检查服务器,看看用户名是否可用。现在我不希望每次键入一个键时都调用它,而是希望它能够检测用户何时停止键入

目前这是我的代码

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变量(或使其成为线程安全属性)时,因为它将是多线程环境。