You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinForm中MySqlConnection异步方法阻塞UI,表现如同步方法

WinForm异步方法导致进度条延迟显示问题

这是一个WinForm应用,ProgressBarz是我自定义的简单进度条,但它只会在ImportaOrdiniAsync方法完全执行完成后才会显示,整个方法的表现和同步方法毫无区别。

相关代码

private async void ultraButtonImporta_Click(object sender, EventArgs e)
{
    if (ultraComboStagione.Value != null)
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.Title = "Seleziona file da Importare";
        openFileDialog.DefaultExt = "xlsx";
        openFileDialog.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";

        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            var task = ImportaOrdiniAsync(openFileDialog.FileName,
                ultraComboStagione.Value.ToString());
            ProgressBarz caricamento = new ProgressBarz ();
            caricamento.Show();
            Application.OpenForms["OrdiniLimiti"].Enabled = false;
            await task;
            caricamento.Close();
            Application.OpenForms["OrdiniLimiti"].Enabled = true;
        }
        else
        {
            MessageBox.Show("Selezionare un file Excel!");
        }
    }
    else
    {
        MessageBox.Show("Selezionare una Stagione!");
    }
}

private async Task ImportaOrdiniAsync(string fileName, string stagione)
{
    Workbook wb = Workbook.Load(fileName);
    Worksheet ws = wb.Worksheets[0];

    for (int i = 1; i < ws.Rows.Count(); i++)
    {
        //Validation Here...

        int idOrdine = await IsOrdinePresenteAsync(codiceCliente, stagione);
        if (idOrdine != -1)
        {
            //Other stuff
        }
        else
        {
            //Other stuff
        }
    }

    //Other stuff
}

private async Task<int> IsOrdinePresenteAsync(string codiceCliente, string stagione)
{
    using (MySqlConnection conn = new MySqlConnection(
        AdoFunction.brMySqlConnection.brMyStringConnection))
    {
        MySqlCommand cmd = new MySqlCommand("SELECT id from table " +
            "WHERE field1 = @codiceCliente AND field2 = @stagione", conn);
        cmd.Parameters.AddWithValue("@codiceCliente", codiceCliente);
        cmd.Parameters.AddWithValue("@stagione", stagione);

        await conn.OpenAsync();
        object result = await cmd.ExecuteScalarAsync();
        if (result != null)
        {
            return (int)result;
        }

        return -1;
    }
}

问题出在IsOrdinePresenteAsync方法中的OpenAsync()或ExecuteScalarAsync()调用上。但如果我在IsOrdinePresenteAsync里替换成await Task.Delay,进度条就能正常显示。

问题原因与解决方案

核心原因

代码里的Workbook.Load(fileName)是同步阻塞操作,如果Excel文件体积较大,这一步会直接卡住UI线程,导致进度条还没来得及渲染,就被后续操作拖到方法结束才显示。另外ws.Rows.Count()如果是同步计算行数,也会进一步阻塞UI。

虽然IsOrdinePresenteAsync用了异步数据库方法,但UI线程已经被前面的同步Excel加载操作占住,根本没机会更新进度条。而Task.Delay是真正释放UI线程的异步操作,所以进度条能正常显示。

修复步骤

  1. 异步加载Excel文件:把同步的Excel加载操作放到后台线程,避免阻塞UI:
Workbook wb = await Task.Run(() => Workbook.Load(fileName));
  1. 异步获取行数:如果ws.Rows.Count()是同步计算逻辑,同样用Task.Run包裹:
int rowCount = await Task.Run(() => ws.Rows.Count());
for (int i = 1; i < rowCount; i++)
{
    // 后续逻辑不变
}
  1. 异步化所有同步阻塞操作:检查//Validation Here...和//Other stuff里的代码,如果有同步耗时操作,都用Task.Run包裹后await,保证UI线程能及时响应进度条的渲染和更新。

这样修改后,UI线程不会被同步操作阻塞,进度条就能在ImportaOrdiniAsync执行过程中正常显示了。

内容的提问来源于stack exchange,提问作者Simone D.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:25:31