简体   繁体   English

与线程计时器异步/等待

[英]async/await with thread timer

I was able resolve the issue with the input form Stephen Cleary. 我可以使用输入表单Stephen Cleary解决此问题。 Please see update 3. 请参阅更新3。

I have a Windows Forms application that has a method with the async modifier. 我有一个Windows Forms应用程序,该应用程序具有带有async修饰符的方法。 If the method is called inside a button's click event it does not block the UI thread. 如果在按钮的click事件中调用该方法,则不会阻塞UI线程。 However, when I call it inside a timer as a callback it freezes the UI. 但是,当我在计时器内部将其作为回调调用时,它将冻结UI。 I could not figure out what I am doing wrong here. 我无法弄清楚我在做什么错。 Please see below my code. 请看下面我的代码。 This is just a sample project for demonstration purposes. 这只是一个示例项目,用于演示。

public Form1()
{
    InitializeComponent();            
}

private async void formCloseAsync()
{
    shutdown stf = new shutdown();
    stf.StartPosition = FormStartPosition.CenterScreen;
    stf.Show();
    var task = Task.Factory.StartNew(processClose);
    await task;
}

private void processClose()
{
    Thread.Sleep(5000);
    Environment.Exit(1);
}

private void simpleButtonAsync_Click(object sender, EventArgs e)
{
    formCloseAsync();
}        

private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
    Timer _shutdownTimer = new Timer(delegate
    {
       formCloseAsync();
    }, null, 5000, Timeout.Infinite);
}

Update 1: Thanks All for your valuable input. 更新1:谢谢大家的宝贵意见。 Please see the updated code below 请在下面查看更新的代码

public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private void formCloseAsync()
    {
        shutdown stf = new shutdown();
        stf.StartPosition = FormStartPosition.CenterScreen;
        stf.Show();

        Task.Run(async ()=>
            { 
                await Task.Delay(5000);
                Environment.Exit(1);
            }
        );
    }

    private void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

However I still have the same issue. 但是我仍然有同样的问题。 shutdown stf is blocked when called inside timer callback. 在内部计时器回调中调用shutdown stf时被阻止。 Main UI is okay. 主界面还可以。 No issue with that. 没问题。 I just want the shutdown(stf) GUI to be responsive when created from timer call back. 我只希望从计时器回调创建shutdown(stf)GUI时可以响应。 Shutdown GUI has a progress bar. 关机GUI带有进度条。

Update 3: 更新3:

Here is the final code 这是最终代码

public partial class Form1 : Form
{
    readonly shutdown _stf = new shutdown();
    public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private async Task formCloseAsync()
    {

        try
        {
            BeginInvoke(new MethodInvoker(delegate
            {

                _stf.StartPosition = FormStartPosition.CenterScreen;
                _stf.Show();
            }));
            await Task.Run( async () =>
                            {
                                await Task.Delay(5000);
                            });

        }
        catch (Exception ex)
        {

            MessageBox.Show(ex.ToString());

        }
        finally
        {
            Environment.Exit(1);
        }

    }

    private  void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
         await formCloseAsync();
    }

Use Task.Delay instead: 使用Task.Delay代替:

await Task.Delay(5000);

Since Thread.Sleep actually blocks the current thread and should not be used within an async method. 由于Thread.Sleep实际上阻​​止了当前线程,因此不应在异步方法中使用。

You can find out more about this here: When to use Task.Delay, when to use Thread.Sleep? 您可以在此处找到有关此内容的更多信息: 什么时候使用Task.Delay,什么时候使用Thread.Sleep?

However, when I call it inside a timer as a callback it freezes the UI. 但是,当我在计时器内部将其作为回调调用时,它将冻结UI。

You can't access UI elements from background threads (I'm guessing stf.Show(); is showing a dialog). 您不能从后台线程访问UI元素(我猜是stf.Show();正在显示一个对话框)。 The easiest fix is probably to replace System.Threading.Timer with Windows.Forms.Timer . 最简单的修复方法可能是将System.Threading.Timer替换为Windows.Forms.Timer

Other notes: 其他说明:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM