【问题标题】:async/await with thread timer带线程计时器的异步/等待
【发布时间】:2016-09-13 15:01:25
【问题描述】:

我能够使用输入表单 Stephen Cleary 解决问题。请参阅更新 3。

我有一个带有 async 修饰符的方法的 Windows 窗体应用程序。如果在按钮的单击事件中调用该方法,它不会阻塞 UI 线程。但是,当我在计时器内将其作为回调调用时,它会冻结 UI。我无法弄清楚我在这里做错了什么。请看下面我的代码。这只是一个用于演示目的的示例项目。

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);
}

更新 1: 谢谢大家的宝贵意见。请参阅下面的更新代码

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);
    }

但是我仍然有同样的问题。在计时器回调中调用时,shutdown stf 被阻止。主界面没问题。没有问题。我只希望从计时器回调创建的shutdown(stf)GUI能够响应。关机 GUI 有一个进度条。

更新 3:

这是最终代码

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();
    }

【问题讨论】:

    标签: c# winforms asynchronous timer


    【解决方案1】:

    改用Task.Delay

    await Task.Delay(5000);
    

    由于Thread.Sleep 实际上阻塞了当前线程并且不应该在异步方法中使用。

    您可以在此处了解更多信息:When to use Task.Delay, when to use Thread.Sleep?

    【讨论】:

    • 睡眠是从后台线程调用的,所以这不是他的问题。他应该改变它,但这不会导致他声称自己遇到的问题。
    【解决方案2】:

    但是,当我在计时器内将其作为回调调用时,它会冻结 UI。

    您无法从后台线程访问 UI 元素(我猜 stf.Show(); 正在显示一个对话框)。最简单的解决方法可能是将System.Threading.Timer 替换为Windows.Forms.Timer

    其他说明:

    【讨论】:

    • 嗨@stephen 非常感谢您的意见。我已经更新了我原来的帖子。请看上面。我可能没有正确地说出哪个 UI 被冻结了。它的关闭 UI 在调用表单计时器时没有响应..
    • @IamaC:同样的答案也适用:不要从后台线程运行 UI 代码。
    • 谢谢@stephen。我能够通过您的输入解决问题。请参阅更新 3
    猜你喜欢
    • 1970-01-01
    • 2020-07-08
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多