VB.Net:如何将DataGridView选中行数据显示到另一窗体文本框?
我帮你梳理下问题所在,以及对应的解决办法:
核心问题分析
你的代码之所以没效果,主要有两个关键原因:
1. 数据获取的时机不对
你把获取选中行数据的代码放在了CellContentClick事件里,但这个事件只有当你点击DataGridView单元格内的具体内容(比如按钮列的按钮、单元格里的文本)时才会触发。而你的操作流程是先点击选中DataGridView的某一行(可能点击的是行的空白区域或者单元格但没触发CellContentClick),再点击窗体上的编辑按钮——这时候CellContentClick根本没执行,那些公共变量自然都没被赋值,EditPage里当然拿不到数据。
2. 直接访问窗体类的非共享变量存在风险
你在EditPage里用Main.id这种方式访问变量,本质是访问Main窗体类的默认实例。但如果你的Main窗体不是通过默认实例创建的(比如代码里用New Main()打开的),那这个默认实例的变量是空的,和你正在操作的那个Main窗体实例完全不是同一个,自然拿不到正确的数据。
具体解决办法
我推荐两种更可靠的方案,你可以选一种适合自己的:
方案一:用构造函数直接传递数据(最规范的方式)
这种方式不需要公共变量,直接在打开编辑窗体时把选中行的数据传过去,避免全局变量的各种问题:
第一步:给EditPage添加带参数的构造函数
在EditPage.vb里添加以下代码:
' 自定义构造函数,接收选中行的所有数据 Public Sub New(id As Integer, firstname As String, lastname As String, birthdate As String, position As String, sex As String, address As String, contact_num As String, email As String) ' 必须先调用InitializeComponent()初始化窗体控件 InitializeComponent() ' 直接把数据赋值给对应的控件 firstname_txtbox.Text = firstname lastname_txtbox.Text = lastname DateTimePicker1.Text = birthdate position_txtbox.Text = position sex_combo.Text = sex address_txtbox.Text = address contact_mask.Text = contact_num email_txtbox.Text = email End Sub
第二步:修改Main窗体的编辑按钮点击事件
在Main.vb的Button3_Click事件里,直接获取选中行数据并传递给EditPage:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click ' 先判断是否选中了行 If tblAttendance.CurrentRow Is Nothing Then MessageBox.Show("请先选中一行数据再编辑!", "提示") Return End If Dim result As Integer = MessageBox.Show("Are you sure you want to Edit the Info?", "Validation", MessageBoxButtons.YesNoCancel) If result = DialogResult.Yes Then Dim row As DataGridViewRow = tblAttendance.CurrentRow Try ' 转换并获取每行的数据(注意处理可能的空值) Dim id As Integer = If(row.Cells(0).Value Is DBNull.Value, 0, Convert.ToInt32(row.Cells(0).Value)) Dim firstname As String = If(row.Cells(1).Value Is DBNull.Value, "", row.Cells(1).Value.ToString()) Dim lastname As String = If(row.Cells(2).Value Is DBNull.Value, "", row.Cells(2).Value.ToString()) Dim birthdate As String = If(row.Cells(3).Value Is DBNull.Value, "", row.Cells(3).Value.ToString()) Dim position As String = If(row.Cells(4).Value Is DBNull.Value, "", row.Cells(4).Value.ToString()) Dim sex As String = If(row.Cells(5).Value Is DBNull.Value, "", row.Cells(5).Value.ToString()) Dim address As String = If(row.Cells(6).Value Is DBNull.Value, "", row.Cells(6).Value.ToString()) Dim contact_num As String = If(row.Cells(7).Value Is DBNull.Value, "", row.Cells(7).Value.ToString()) Dim email As String = If(row.Cells(8).Value Is DBNull.Value, "", row.Cells(8).Value.ToString()) ' 创建EditPage实例并传递数据 Dim editForm As New Edit_Page(id, firstname, lastname, birthdate, position, sex, address, contact_num, email) editForm.Show() Catch ex As Exception MessageBox.Show("数据转换出错:" & ex.Message, "错误") End If ElseIf result = DialogResult.No Then MessageBox.Show("Edit Cancelled", "Message") End If End Sub
方案二:改进公共变量的使用方式(如果你坚持用公共变量)
如果你还是想用公共变量传递数据,需要修改两个地方:
第一步:把数据获取移到SelectionChanged事件
在Main.vb里添加SelectionChanged事件,确保选中行时就更新公共变量:
Private Sub tblAttendance_SelectionChanged(sender As Object, e As EventArgs) Handles tblAttendance.SelectionChanged If tblAttendance.CurrentRow IsNot Nothing Then Dim row As DataGridViewRow = tblAttendance.CurrentRow Try ' 处理空值和类型转换 id = If(row.Cells(0).Value Is DBNull.Value, 0, Convert.ToInt32(row.Cells(0).Value)) firstname = If(row.Cells(1).Value Is DBNull.Value, "", row.Cells(1).Value.ToString()) lastname = If(row.Cells(2).Value Is DBNull.Value, "", row.Cells(2).Value.ToString()) birthdate = If(row.Cells(3).Value Is DBNull.Value, "", row.Cells(3).Value.ToString()) position = If(row.Cells(4).Value Is DBNull.Value, "", row.Cells(4).Value.ToString()) sex = If(row.Cells(5).Value Is DBNull.Value, "", row.Cells(5).Value.ToString()) address = If(row.Cells(6).Value Is DBNull.Value, "", row.Cells(6).Value.ToString()) contact_num = If(row.Cells(7).Value Is DBNull.Value, "", row.Cells(7).Value.ToString()) email = If(row.Cells(8).Value Is DBNull.Value, "", row.Cells(8).Value.ToString()) Catch ex As Exception MessageBox.Show("获取选中行数据失败:" & ex.Message, "错误") End If End If End Sub
第二步:传递当前Main窗体实例给EditPage
在EditPage.vb里添加一个属性来接收Main窗体实例:
Public Property ParentMainForm As Main ' 这里的Main是你的Main窗体类名
然后修改EditPage的Load事件:
Private Sub Edit_Page_Load(sender As Object, e As EventArgs) Handles MyBase.Load If ParentMainForm IsNot Nothing Then ' 通过传递过来的实例访问公共变量 firstname_txtbox.Text = ParentMainForm.firstname lastname_txtbox.Text = ParentMainForm.lastname DateTimePicker1.Text = ParentMainForm.birthdate position_txtbox.Text = ParentMainForm.position sex_combo.Text = ParentMainForm.sex address_txtbox.Text = ParentMainForm.address contact_mask.Text = ParentMainForm.contact_num email_txtbox.Text = ParentMainForm.email End If End Sub
最后修改Main窗体的编辑按钮事件:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click If tblAttendance.CurrentRow Is Nothing Then MessageBox.Show("请先选中一行数据!", "提示") Return End If Dim result As Integer = MessageBox.Show("Are you sure you want to Edit the Info?", "Validation", MessageBoxButtons.YesNoCancel) If result = DialogResult.Yes Then Dim editForm As New Edit_Page() editForm.ParentMainForm = Me ' 传递当前Main窗体的实例 editForm.Show() ElseIf result = DialogResult.No Then MessageBox.Show("Edit Cancelled", "Message") End If End Sub
额外注意事项
- 建议把DataGridView的
SelectionMode属性设置为FullRowSelect,这样点击行的任何区域都会选中整行,方便获取CurrentRow。 - 一定要处理单元格值为
DBNull的情况,避免空值转换时抛出异常。
内容的提问来源于stack exchange,提问作者Nikko Tongoy

