foreach循环执行SQL请求时如何实现实时更新的进度条
核心原因
WPF的UI渲染和事件回调都运行在UI主线程,你当前的SQL执行和foreach循环都是同步逻辑,会阻塞UI线程,导致进度条的属性变更无法被实时渲染,只有整个UID_SendRestore_Click方法执行完毕后,UI线程才会一次性处理所有待更新的UI变更,所以你会看到进度条直接填满。
修改方案
我们通过async/await异步执行SQL请求,避免阻塞UI线程,每次SQL执行完成后实时更新进度条,修改后的代码如下:
// 首先给Click方法加上async修饰符 private async void UID_SendRestore_Click(object sender, RoutedEventArgs e) { Bd_IsUpdate = isAnyChecked; if (RestoreDatabase.IsChecked == false && ReorganizeDatabase.IsChecked == false) { MessageBox.Show("Vous devez sélectionner au minimum un choix à appliquer", "Absence de sélection", MessageBoxButton.OK, MessageBoxImage.Exclamation); return; } // 先把进度条最大值一次性设置好,不用放在循环里重复赋值 pbStatus.Maximum = isAnyChecked; pbStatus.Value = 0; // 把选中的项先查出来存好,避免循环中反复遍历数据源 var checkedItems = (from DBtoRestore x in dgDBtoRestore.Items where x.IsChecked select x).ToList(); foreach (DBtoRestore item in checkedItems) { if (RestoreDatabase.IsChecked == true) { try { // 建议数据库连接用using声明,用完自动释放,不要复用全局连接对象更安全 using (SqlConnection cnx = new SqlConnection()) { if (cmbAuthentification.Text.Equals("Windows")) { cnx.ConnectionString = "Server = " + txtServerName.Text + "; Integrated Security = SSPI;"; } else if (cmbAuthentification.Text.Equals("SQL Server")) { cnx.ConnectionString = "Server = " + txtServerName.Text + "; User ID =" + txtUserID.Text + "; Password=" + txtUserPwd.Password + ";"; } // 异步打开连接,不阻塞UI await cnx.OpenAsync(); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = cnx; cmd.CommandText = @"USE [" + item.CUID_dbname + "];" + ...; cmd.CommandTimeout = 0; // 异步执行SQL,执行期间UI线程可以正常渲染进度条 SqlDataReader dr = await cmd.ExecuteReaderAsync(); dr.Close(); } cnx.Close(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "OOoopssss !!!", MessageBoxButton.OK, MessageBoxImage.Hand); Bd_IsUpdate++; } } // 每次处理完一个项,更新进度条值,await之后的代码默认回到UI线程执行,可直接操作UI Bd_IsUpdate--; pbStatus.Value += 1; } }
关键说明
- 给
UID_SendRestore_Click添加async修饰符,所有IO操作(打开连接、执行SQL)都使用对应的异步API(OpenAsync、ExecuteReaderAsync)搭配await调用,执行过程不会阻塞UI线程 - 进度条的更新放在每次SQL处理完成之后,此时UI线程处于空闲状态,会立即渲染进度条变更
- 建议不要复用全局的SqlConnection、SqlCommand对象,每次操作新建连接并通过using自动释放,避免多线程操作或异常场景下的资源泄漏
注意:该方案要求.NET Framework版本 >=4.5 或使用.NET Core/.NET 5+,默认已支持SqlClient的异步API。
内容的提问来源于stack exchange,提问作者Fabrice Bertrand
相关产品推荐
相关产品推荐

