等待后无法访问winforms标签?

时间:2017-10-08 19:59:20

标签: c# async-await

我有一个长时间运行的方法,我做了异步。我也使我的按钮单击处理程序异步,但是当我尝试在完成长方法后单击我的按钮时,它会告诉我它无法从另一个线程访问它。这是代码:

    private void Migrate()
    {
        for (int i = 2; i <= excelData.GetUpperBound(0); i++)
        {
            var poco = new ExpandoObject() as IDictionary<string, object>;

            foreach (var column in distributionColumnExcelHeaderMappings)
            {
                if (column.ColumnIndex > 0)
                {
                    var value = excelData[i,column.ColumnIndex]?.ToString();

                    poco.Add(column.DistributionColumnName.Replace(" ", ""), value);
                }

            }

            pocos.Add(poco);
        }

            migrationRepository.BulkInsert(insertToTable, "Id", pocos);
    }

    private async void btnMigrate_Click(object sender, EventArgs e)
    {
        Task task = new Task(()=> Migrate());
        task.Start();
        lblStatus.Text = "Migrating data....";

        await task;

        lblStatus.Text = "Migration Complete";
    }

单击该按钮时,我会看到状态Migrating data....。完成后,它会在lblStatus.Text = "Migration Complete"上抛出错误。我想等待之后,它会回到UI线程吗?

我清除了大部分代码,它仍然会抛出相同的错误。这是一个VSTO excel插件。这可能是问题的一部分吗?

private void Migrate()
{

}

private async void btnMigrate(object sender, EventArgs e)
{
Task.Run(()=>Migrate());
lblStatus.Text = "Done"; //still get error here
}

1 个答案:

答案 0 :(得分:0)

尝试将代码更新为以下内容:

不是创建任务然后手动启动它,而是将其更新为等待Task.Run:

private async void btnMigrate_Click(object sender, EventArgs e)
{
    lblStatus.Text = "Migrating data....";

    await Task.Run(()=> Migrate());

    lblStatus.Text = "Migration Complete";
}

修改

您可以使用辅助方法来检查在更新之前是否需要调用标签。

private async void btnMigrate_Click(object sender, EventArgs e)
{
    SetLabelText(lblStatus, "Migrating data....");

    await Task.Run(()=> Migrate());

    SetLabelText(lblStatus, "Migration complete.");
}

private void SetLabelText(Label label, string text)
{
    if (label.InvokeRequired)
    {
        label.BeginInvoke((MethodInvoker) delegate() {label.Text = text;});    
    }
    else
    {
        label.Text = text; 
    }
}