C# 如何异步等待x秒,然后执行某些操作?

C# 如何异步等待x秒,然后执行某些操作?,c#,winforms,forms,sleep,wait,C#,Winforms,Forms,Sleep,Wait,我知道在C#和Windows窗体中有和System.Windows.Forms.Timer。我似乎无法想出如何等待X秒,然后再做其他事情,而不锁定线程 我有一张带按钮的表格。点击按钮时,计时器应启动并等待5秒。在这5秒钟之后,窗体上的其他控件被涂成绿色。当使用Thread.Sleep时,整个应用程序将在5秒钟内失去响应-那么我如何“在5秒钟后做一些事情”您的应用程序将挂起,因为您正在调用主UI线程上的5秒钟睡眠/等待。将sleep/wait/which操作放在一个单独的线程中(实际上System

我知道在C#和Windows窗体中有和
System.Windows.Forms.Timer
。我似乎无法想出如何等待X秒,然后再做其他事情,而不锁定线程


我有一张带按钮的表格。点击按钮时,计时器应启动并等待5秒。在这5秒钟之后,窗体上的其他控件被涂成绿色。当使用
Thread.Sleep
时,整个应用程序将在5秒钟内失去响应-那么我如何“在5秒钟后做一些事情”

您的应用程序将挂起,因为您正在调用主UI线程上的5秒钟睡眠/等待。将sleep/wait/which操作放在一个单独的线程中(实际上System.Windows.Forms.Timer应该为您执行此操作),并在完成时调用将某些控件变为绿色的操作。记住检查invokererequired。下面是一个简短的示例(SetText可以从另一个线程调用,如果是,则该调用将在启用textbox的主UI线程上调用):


我从(非常值得一读!)中获取了示例。

您可以启动一个执行操作的异步任务:

Task.Factory.StartNew(()=>
{
    Thread.Sleep(5000);
    form.Invoke(new Action(()=>DoSomething()));
});
[编辑]

要在中传递间隔,只需将其存储在变量中:

int interval = 5000;
Task.Factory.StartNew(()=>
{
    Thread.Sleep(interval);
    form.Invoke(new Action(()=>DoSomething()));
});

[/EDIT]你看错了。 单击按钮,它将启动一个间隔为x秒的计时器。当它们启动时,eventhandler将执行任务

那你不想发生什么呢

当x秒过去时

当任务正在执行时

例如,如果是,您不希望在延迟和任务完成之前单击按钮。在按钮单击处理程序中禁用它,并在任务完成时启用它

如果您只想在任务开始前延迟5秒,那么您应该将开始延迟传递给任务,让它处理好它。

(抄写自Ben作为注释)

只需使用System.Windows.Forms.Timer。将计时器设置为5秒,并处理滴答声事件。当事件触发时,执行该操作

…并在执行工作之前禁用计时器(IsEnabled=false),以抑制秒数

勾号事件可能会在无法修改gui的另一个线程上执行,您可以捕获以下内容:

private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();

    private void StartAsyncTimedWork()
    {
        myTimer.Interval = 5000;
        myTimer.Tick += new EventHandler(myTimer_Tick);
        myTimer.Start();
    }

    private void myTimer_Tick(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            /* Not on UI thread, reenter there... */
            this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
        }
        else
        {
            lock (myTimer)
            {
                /* only work when this is no reentry while we are already working */
                if (this.myTimer.Enabled)
                {
                    this.myTimer.Stop();
                    this.doMyDelayedWork();
                    this.myTimer.Start(); /* optionally restart for periodic work */
                }
            }
        }
    }

只是为了完整性:使用async/await,可以延迟执行非常简单的操作(一次,永远不要重复调用):

有关更多信息,请参阅MSDN中的“async and await”。

@eFloh在标有“答案”的帖子中写道:

勾号事件可能会在另一个无法修改的线程上执行 你的gui,你可以捕捉到这个

医生不是这么说的。
示例代码中使用的是System.Windows.Forms.Timer。
这是一个窗体计时器。
根据C#文档,计时器事件在UI线程上引发

此Windows计时器专为单线程环境设计,其中 UI线程用于执行处理。它要求用户 代码有一个UI消息pump可用,并且始终从相同的位置运行 线程

另请参见

您尝试过吗

public static Task Delay(
    int millisecondsDelay
)
您可以这样使用:

await Task.Delay(5000);

参考:

您可以按照您希望的方式等待UI线程

Task.Factory.StartNew(async() =>
{
    await Task.Delay(2000);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});
如果您使用的是.Net Framework 4.5或更高版本,则可以使用
Task.Run
而不是
Task.Factory.StartNew
,如下所示

int millisecondsDelay = 2000;

Task.Run(async() =>
{
    await Task.Delay(millisecondsDelay);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});

我想你要找的是
System.Timers
。。。我认为您不需要为正在尝试的操作设置CWND计时器:请看一个示例。它应该会起作用。
Task.Factory.StartNew(async() =>
{
    await Task.Delay(2000);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});
int millisecondsDelay = 2000;

Task.Run(async() =>
{
    await Task.Delay(millisecondsDelay);

    // it only works in WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // Do something on the UI thread.
    });
});