我的程序中有三个DataViews
,每个都连接了一个DataTable
,我从SqlAdapter
中完全更新(通过合并和删除一些行)。更新是在异步方法中完成的,需要包装在我自己的Task.Run(...)
操作中。更新后,DataGridViews
不显示更新的数据,尽管DataGridView
、DataView
和DataTable
的组合通常会处理这个问题。
这似乎破坏了绑定到DataViews
的DataGridViews
的自动刷新。观察DataGridViews
的DataBindingComplete
事件表明,当我在异步方法中更新基础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窗体,它可能应该。