在异步方法中更新数据表内容不会正确刷新绑定的数据网格视图



我的程序中有三个DataViews,每个都连接了一个DataTable,我从SqlAdapter中完全更新(通过合并和删除一些行)。更新是在异步方法中完成的,需要包装在我自己的Task.Run(...)操作中。更新后,DataGridViews不显示更新的数据,尽管DataGridViewDataViewDataTable的组合通常会处理这个问题。

这似乎破坏了绑定到DataViewsDataGridViews的自动刷新。观察DataGridViewsDataBindingComplete事件表明,当我在异步方法中更新基础DataTables时,它没有正确触发。更新所有三个DataTables时,我只观察到在更新过程中为其中一个DataGridViews触发的事件,其中DataTable中只有一行......异步方法完成更新后,还有更多行永远不会显示。一旦我更改列的排序,我的DataGridViews就会显示正确的更新数据。

在触发刷新的按钮事件中,我做了另一个测试:

private async void AddSomethingToolStripButton_Click(object sender, EventArgs e) {
if (sender is ToolStripButton button) {
int test1 = DataGridView1.RowCount; // 4
int test2 = ((DataGridView1.DataSource as BindingSource).DataSource as DataView).Count; // 4
/* Calls async method to write new value to DB and calls more async methods to refresh
* all the DataTables with the new data which also effects the one in this example */
await controller.AddSomethingToSqlDbAndRefreshDataTableAsync();
int test3 = DataGridView1.RowCount; // Still 4
int test4 = ((DataGridView1.DataSource as BindingSource).DataSource as DataView).Count; // 5
}
}

这些值永远不会同步,因为它们应该是同步的。在尝试通过在DataGridView上调用Refresh或在Binding上调用ReadValues来手动刷新后,我设法通过在感觉不太正确的BindingSource上调用ResetBindings来使其工作。

我错过了什么吗?我不应该将这些数据结构和机制与async/await模式结合使用吗?

编辑 - 刷新方法的示例:

private async Task RefreshDataViewAsync(string query, DataView view) {
await Task.Run(() => {
using var con = new SqlConnection(sqlConnectionString);
using var adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(query, con);
var newtable = new DataTable();
adapter.FillSchema(newtable, SchemaType.Source);
foreach (DataColumn col in newtable.Columns) {
if (ColumnValueTypeMapping.TryGetValue(col.ColumnName, out Type coltype)) {
col.DataType = coltype;
}
}
adapter.Fill(newtable);
view.Table.Merge(newtable, false);
/* Remove rows that are not present anymore */
var rows2del = new List<DataRow>();
string[] primarykeys = view.Table.PrimaryKey.Select(keycol => keycol.ColumnName).ToArray();
foreach (DataRow row in view.Table.Rows) {
if (!newtable.Rows.Contains(primarykeys.Select(key => row.Field<object>(key)).ToArray())) {
rows2del.Add(row);
}
}
rows2del.ForEach(row => row.Delete());
view.Table.AcceptChanges();
});
}

您应该将 UI 代码与非 UI 代码分开。

private async void AddSomethingToolStripButton_Click(object sender, EventArgs e)
{
DataGridView1.DataSource = await GetDataAsync();
}

您的GetDataAsync方法可能会使用Task.Run。事实上,鉴于它是Windows窗体,它可能应该。

最新更新