如何在Visual Basic 2015中通过两个窗体刷新DataGridView?
解决跨窗体DataGridView刷新问题(VB.NET)
首先,先帮你修正frmAddBooks里的插入代码——你现在同时混用了字符串拼接SQL和参数化查询,这是错误的,既容易引发SQL注入风险,也没真正发挥参数化查询的作用。先把这部分改对:
Imports System.Data.OleDb Public Class frmAddBooks ' 定义事件:当书籍添加成功时触发 Public Event BookAddedSuccessfully() Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click Dim cn As New OleDbConnection Dim cm As New OleDbCommand Try With cn .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\Assessment of the CKC Library System\Database.accdb" .Open() End With With cm .Connection = cn .CommandType = CommandType.Text ' 使用参数占位符替代字符串拼接,彻底避免SQL注入 .CommandText = "INSERT INTO [Books] ([ISBN],[BookTitle],[Author],[Category],[Foreword],[YearPublished], [Quantity]) VALUES (@ISBN, @BookTitle, @Author, @Category, @Foreword, @YearPublished, @Quantity)" ' 正确添加参数并赋值 .Parameters.Add(New OleDbParameter("@ISBN", OleDbType.VarChar, 30)).Value = Me.txtISBN.Text .Parameters.Add(New OleDbParameter("@BookTitle", OleDbType.VarChar, 255)).Value = Me.txtBookTitle.Text .Parameters.Add(New OleDbParameter("@Author", OleDbType.VarChar, 255)).Value = Me.txtAuthor.Text .Parameters.Add(New OleDbParameter("@Category", OleDbType.VarChar, 255)).Value = Me.cboCategory.Text .Parameters.Add(New OleDbParameter("@Foreword", OleDbType.VarChar, 255)).Value = Me.txtForeword.Text .Parameters.Add(New OleDbParameter("@YearPublished", OleDbType.VarChar, 255)).Value = Me.cboYearPublished.Text .Parameters.Add(New OleDbParameter("@Quantity", OleDbType.VarChar, 255)).Value = Me.cboQuantity.Text cm.ExecuteNonQuery() MsgBox("Book added.", MsgBoxStyle.Information, "Saved Successfully!") ' 清空输入框 Me.txtISBN.Text = "" Me.txtBookTitle.Text = "" Me.txtAuthor.Text = "" Me.txtForeword.Text = "" cboCategory.SelectedIndex = -1 cboQuantity.SelectedIndex = -1 cboYearPublished.SelectedIndex = -1 ' 触发书籍添加成功事件 RaiseEvent BookAddedSuccessfully() End With Catch ex As Exception MsgBox($"Error: {ex.Message}", MsgBoxStyle.Exclamation, "Error") Finally ' 确保数据库连接关闭并释放资源 If cn.State = ConnectionState.Open Then cn.Close() End If cn.Dispose() cm.Dispose() End Try End Sub Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click Hide() End Sub End Class
接下来解决跨窗体刷新的核心问题——你之前的frmSearchUpdateBooks用DataSet缓存了数据,添加新数据后没有重新从数据库拉取最新内容,所以DataGridView显示旧数据。这里给你两种简单易上手的方案:
方案一:通过事件通知刷新(推荐,低耦合)
这种方法符合面向对象设计,两个窗体之间通过事件通信,耦合度低,适合长期维护。
在frmSearchUpdateBooks中,打开frmAddBooks时订阅它的BookAddedSuccessfully事件,事件触发时重新填充DataGridView:
Public Class frmSearchUpdateBooks ' 保存添加窗体的实例 Private addBookForm As frmAddBooks Private Sub frmSearchUpdateBooks_Load(sender As Object, e As EventArgs) Handles MyBase.Load Me.BooksTableAdapter.Fill(Me.DatabaseDataSet.Books) ' 初始化添加窗体并订阅事件 addBookForm = New frmAddBooks AddHandler addBookForm.BookAddedSuccessfully, AddressOf RefreshBookData End Sub ' 封装刷新数据的方法 Private Sub RefreshBookData() Me.DatabaseDataSet.Books.Clear() ' 清空旧数据 Me.BooksTableAdapter.Fill(Me.DatabaseDataSet.Books) ' 拉取最新数据 Me.DataGridView1.Refresh() End Sub ' 假设你有打开添加窗体的按钮,比如btnAddBook_Click Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click addBookForm.Show() End Sub ' 保留你原有的其他方法 Private Sub BooksBindingNavigatorSaveItem_Click(sender As Object, e As EventArgs) Me.Validate() Me.BooksBindingSource.EndEdit() Me.TableAdapterManager.UpdateAll(Me.DatabaseDataSet) End Sub Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click Try BooksBindingSource.EndEdit() BooksTableAdapter.Update(DatabaseDataSet) MsgBox("Successfully saved.", MsgBoxStyle.OkOnly, "Success!") RefreshBookData() ' 保存后也可调用刷新 Catch ex As Exception MsgBox("Please fill all the information needed. If all informations are filled up, please re-check the ISBN as some book might have the same ISBN as you are entering.", MsgBoxStyle.OkOnly, "Error!") End Try End Sub Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click BooksBindingSource.RemoveCurrent() BooksBindingSource.EndEdit() MsgBox("Item successfully deleted!", MsgBoxStyle.OkOnly, "Success!") End Sub Private Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click Try Me.Validate() Me.BooksBindingSource.EndEdit() Me.BooksTableAdapter.Update(DatabaseDataSet) MsgBox("Updated Successfully!", MsgBoxStyle.OkOnly, "Update Successful!") Catch ex As Exception MsgBox(ex.Message) Finally RefreshBookData() End Try End Sub End Class
方案二:直接查找已打开的窗体实例刷新(简单直接)
如果frmSearchUpdateBooks是始终处于打开状态的,可以在frmAddBooks保存成功后直接找到它的实例并调用刷新方法:
首先在frmSearchUpdateBooks中添加一个公共的刷新方法:
Public Sub RefreshBookData() Me.DatabaseDataSet.Books.Clear() Me.BooksTableAdapter.Fill(Me.DatabaseDataSet.Books) Me.DataGridView1.Refresh() End Sub
然后在frmAddBooks的btnSave_Click方法中,保存成功后添加以下代码:
' 查找已打开的frmSearchUpdateBooks实例 Dim searchForm As frmSearchUpdateBooks = Application.OpenForms.OfType(Of frmSearchUpdateBooks)().FirstOrDefault() If searchForm IsNot Nothing Then searchForm.RefreshBookData() End If
这种方法更直接,但两个窗体的耦合度较高,适合简单场景。
关键总结:
- 问题核心:
frmSearchUpdateBooks的DataSet没有重新从数据库读取最新数据,只要在添加成功后重新执行BooksTableAdapter.Fill就能刷新DataGridView。 - 一定要修正参数化查询的问题,字符串拼接SQL不仅容易出错,还存在严重的安全风险。
内容的提问来源于stack exchange,提问作者Rey Anthony Abarquez Rosalado
相关产品推荐
相关产品推荐

