【问题标题】:Waiting for task to complete on form close [duplicate]在表单关闭时等待任务完成[重复]
【发布时间】:2018-06-13 15:44:09
【问题描述】:

我对 async/await 还很陌生,我在处理表单关闭前未完成的任务时遇到了困难。它在大多数情况下都可以正常工作,但有时我需要检索数据集或修改表,并且查询太慢而无法在 UI 线程关闭之前完成。

我可以使用 Task.Wait(),或者使用 ExecuteNonQuery() 而不是 ExecuteNonQueryAsync(),但我想在表单关闭之前避免死锁。我已经搜索了其他一些帖子,但我仍然对最好的方法有点不确定。

以下示例是在关闭表单之前更新支持呼叫的状态。

private async void frmSupportDetails_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                // Sets call to incomplete if it was pending/transferred
                if (status != "Complete" && status != "Incomplete")
                {
                    dbQuery = "UPDATE SupportCalls SET [Status] = @status, [CompletedNote] = @completedNote WHERE CallNum = @callNum";
                    await sql.executeAsync(dbQuery, new OleDbParameter("@status", "Incomplete"), new OleDbParameter("@completedNote", txtCompletedNote.Text), new OleDbParameter("@callNum", ProgOps.selectedCallNum));
                }

                // Asks to log callback date
                if (promptCallBack == true)
                {
                    DialogResult callbackOption = MessageBox.Show("Would you like to log that you are returning the customer's call?", "Callback Date", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                    if (callbackOption == DialogResult.Yes)
                    {
                        dbQuery = "UPDATE SupportCalls SET CallbackDate = Now() WHERE CallNum = @callNum";
                        await sql.executeAsync(dbQuery, new OleDbParameter("@callNum", ProgOps.selectedCallNum));
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error Occurred - frmClose()", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }
        }

public async Task executeAsync(string dbQuery, params OleDbParameter[] parameters)
        {
            using (var dbConn = new OleDbConnection(CONNECT_STRING))
            using (var dbComm = new OleDbCommand(dbQuery, dbConn))
            {
                if (parameters != null)
                    dbComm.Parameters.AddRange(parameters);

                await dbConn.OpenAsync().ConfigureAwait(false);
                await dbComm.ExecuteNonQueryAsync().ConfigureAwait(false);
            }
        }

【问题讨论】:

  • 这不应该是异步的,因为你没有那样使用它。话虽如此,您为什么担心表单关闭时出现死锁?
  • @RyanJohnson 您可能想阅读我发现的这篇 StackOverflow 帖子,它提供了一个示例,说明如果您一心想要对 FormClosing 事件使用异步,该怎么办,(stackoverflow.com/questions/16656523/…)
  • @RyanWilson 使函数异步不会使其在另一个线程上运行。它只是意味着它在被调用后立即返回。使函数异步的许多可能方法之一是让它在另一个线程中工作,但这绝不是使函数异步的唯一方法。这个特定的示例不是在另一个线程中工作,而是在与数据库进行 IO。
  • @Trey frmSupportDetails 是一个子表单,如果非异步查询遇到任何网络问题,我过去曾遇到过 UI 变得无响应并导致整个程序崩溃的问题。跨度>
  • @Servy 如果它立即返回,那么在方法内部完成的工作是什么?我只是问,因为我一直在尝试阅读 async 并理解它。我认为异步的目的是释放 UI 线程以保持 UI 响应。

标签: c# winforms asynchronous async-await


【解决方案1】:

因为您的表单关闭事件处理程序是一个异步 void,它会在您等待后返回给调用者,这会导致表单继续其关闭过程并完成。您需要取消关闭事件,然后在更新后再次调用 close。您还需要确保用户在您取消的关闭和稍后的真正关闭之间不能做任何事情。比如:

private bool asyncCloseHack = true;
private async void frmSupportDetails_FormClosing(object sender, FormClosingEventArgs e)
    {
         if (asyncCloseHack)
         {
              e.Cancelled = true;
              try
              {
                  LockUserUI();
                  await AsyncTask();
              }
              finally
              {
                  UnlockUserUI();
              }
              asyncCloseHack = false;
              Close();
         }
    }

【讨论】:

    猜你喜欢
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多