如何在不冻结UI的情况下删除大量行?

时间:2016-05-18 18:56:49

标签: c# mysql winforms datagridview backgroundworker

我正在试图弄清楚如何从DataGridView删除大量记录,删除我的意思是运行MySql删除查询并从DataGridView中删除行本身。问题是在不冻结UI的情况下完成所有这些工作。我正在尝试使用BackgroundWorker。我知道它仍然需要暂时执行Invoke()并且它仍然会冻结UI但这些调用发生得相对较快,而其他所有其他东西都会在以后继续运行,就像数据库删除这是最耗费任务一样。如果有更好的事情,那是非常受欢迎的。

我目前的实施显然无效,-1始终为var rows = dataGridView1.SelectedRows; backgroundWorker.RunWorkerAsync(rows); ,如下所示:

点击按钮:

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            using (MySqlConnection con = Database.GetConnection())
            {
                using (MySqlCommand cmd = con.CreateCommand())
                {
                    cmd.Connection = con;
                    con.Open();

                    var SelectedRows =  e.Argument as DataGridViewSelectedRowCollection;
                    int rowIndex = 0;
                    int total = SelectedRows.Count;
                    foreach (DataGridViewRow row in SelectedRows)
                    {
                        int id = getIdByRow_safe(row.Index); //row.Index is -1
        cmd.CommandText = string.Format("delete from xxx where id = {1}", id);

                        bool deleted = cmd.ExecuteNonQuery() == 1;

                        if (!deleted)
                        {
                            /* error handling ... */
                        }

                        int progress = (int)(100.0 / total * ++rowIndex);
                        BackgroundWorker.ReportProgress(progress, row);
                    }
                }
            }
        }

然后是backgroundWork的doWork事件:

  delegate int getIDEventHandler(int i);

    int getIdByRow(int index)
    {
        return (int)dataGridView1.Rows[index].Cells["id"].Value;
    }

    int getIdByRow_safe(int index)
    {
        if (dataGridView1.InvokeRequired)
            return (int) dataGridView1.Invoke(new getIDEventHandler(getIdByRow), new object[] { index });

        return getIdByRow(index);
    }

和getId()函数和族:

{{1}}

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

我建议转换为async / await而不是Background/WorkerHere's the MSDN关于async / await。以下是微软的用法示例:

// Three things to note in the signature:
//  - The method has an async modifier. 
//  - The return type is Task or Task<T>. (See "Return Types" section.)
//    Here, it is Task<int> because the return statement returns an integer.
//  - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync.
    //  - AccessTheWebAsync can't continue until getStringTask is complete.
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
    //  - Control resumes here when getStringTask is complete. 
    //  - The await operator then retrieves the string result from getStringTask.
    string urlContents = await getStringTask;

    // The return statement specifies an integer result.
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
    return urlContents.Length;
}