DataGridView含自动生成slno列导出文本文件时遇空引用错误求解决
问题描述
需要将包含Oracle表字段(region、branch、pos_slno、damage、missing)以及运行时自动生成的slno列的DataGridView数据导出到文本文件,但保留slno列时执行导出会出现“对象引用未设置为对象实例”错误,移除该列后导出功能正常,需保留slno列并解决错误。
相关VB.NET代码
Public Sub stk_rpt_load_data() Datagridview_STK_RPT.Show() Dim ds As New DataSet ds.Tables.Add(dt.Copy()) Dim da As New OracleDataAdapter da = New OracleDataAdapter("select region,branch,pos_slno,damage,missing from POS_STOCK order by branch", con) da.Fill(dt) Datagridview_STK_RPT.DataSource = dt con.Close() End Sub Private Sub REPORTS_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load stk_rpt_load_data() End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim dt As DataTable = New DataTable() For Each column As DataGridViewTextBoxColumn In Datagridview_STK_RPT.Columns dt.Columns.Add(column.Name, column.ValueType) Next For Each row As DataGridViewRow In Datagridview_STK_RPT.Rows Dim dr As DataRow = dt.NewRow() For Each column As DataGridViewTextBoxColumn In Datagridview_STK_RPT.Columns If row.Cells(column.Name).Value IsNot Nothing Then dr(column.Name) = row.Cells(column.Name).Value.ToString() & vbTab & "|" End If Next dt.Rows.Add(dr) Next Dim filePath As String = "D:\" & ComboBox_branch.Text & ".txt" MsgBox("TEXT " & ComboBox_branch.Text & " CREATED IN D:\") DataTableToTextFile(dt, filePath) End Sub Private Sub DataTableToTextFile(ByVal dt As DataTable, ByVal outputFilePath As String) Dim maxLengths As Integer() = New Integer(dt.Columns.Count - 1) {} Dim ln As Integer = 1 For i As Integer = 0 To dt.Columns.Count - 1 maxLengths(i) = dt.Columns(i).ColumnName.Length For Each row As DataRow In dt.Rows If Not row.IsNull(i) Then Dim length As Integer = row(i).ToString().Length If length > maxLengths(i) Then maxLengths(i) = length End If End If Next Next Using sw As StreamWriter = New StreamWriter(outputFilePath, False) sw.WriteLine(" ") sw.WriteLine("---------------------------------------------------------------") sw.WriteLine(" REGION : " & TextBox1.Text & " BRANCH : " & TextBox2.Text & "") sw.WriteLine("---------------------------------------------------------------") sw.WriteLine(" POS STOCK DETAILS AS ON DATE " & DateTimePicker1.Text & "") sw.WriteLine("---------------------------------------------------------------") For i As Integer = 0 To dt.Columns.Count - 1 sw.Write(dt.Columns(i).ColumnName.PadRight(maxLengths(i) + 3)) Next sw.WriteLine() ln = ln + 1 For Each row As DataRow In dt.Rows For i As Integer = 0 To dt.Columns.Count - 1 If Not row.IsNull(i) Then sw.Write(row(i).ToString().PadRight(maxLengths(i) + 2)) Else sw.Write(New String(" "c, maxLengths(i) + 2)) End If Next sw.WriteLine() ln = ln + 1 If ln >= 57 Then sw.WriteLine(Chr(12)) sw.WriteLine("REGION BRANCH POS_SLNO DAMAGE MISSING") ln = 1 End If Next sw.WriteLine("--------------------------------------------------------------") sw.WriteLine("" & TextBox2.Text & " BRANCH - POS STOCK INCLUDING CHARGER : " & dt.Rows.Count) sw.WriteLine("--------------------------------------------------------------") sw.WriteLine(Chr(12)) sw.Close() End Using End Sub Private Sub Datagridview_STK_RPT_RowPostPaint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles Datagridview_STK_RPT.RowPostPaint Datagridview_STK_RPT.Rows(e.RowIndex).Cells(0).Value = (e.RowIndex + 1).ToString End Sub
错误原因分析
- ValueType未设置:自动生成的slno列是手动添加的未绑定列,未指定
ValueType属性,执行dt.Columns.Add(column.Name, column.ValueType)时,column.ValueType为Nothing,触发空引用错误。 - 未处理新增空行:DataGridView默认允许添加新行(
AllowUserToAddRows=True),该行的slno列未被RowPostPaint事件赋值,值为Nothing,后续处理易引发异常。 - 列类型筛选过严:原代码仅遍历
DataGridViewTextBoxColumn类型的列,若slno列类型不符会被跳过,但保留该列时会进入循环,导致类型匹配问题。
解决方案及修改后的代码
修改点1:优化RowPostPaint事件,跳过新增空行
Private Sub Datagridview_STK_RPT_RowPostPaint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles Datagridview_STK_RPT.RowPostPaint ' 不为新增空行赋值序号 If Not Datagridview_STK_RPT.Rows(e.RowIndex).IsNewRow Then Datagridview_STK_RPT.Rows(e.RowIndex).Cells(0).Value = (e.RowIndex + 1).ToString End If End Sub
修改点2:修复Button2_Click中的列添加与行遍历逻辑
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim dt As DataTable = New DataTable() ' 遍历所有DataGridView列,而非仅DataGridViewTextBoxColumn For Each column As DataGridViewColumn In Datagridview_STK_RPT.Columns Dim colType As Type = column.ValueType ' 若列未设置ValueType,默认使用String类型(适配slno列) If colType Is Nothing Then colType = GetType(String) End If dt.Columns.Add(column.Name, colType) Next For Each row As DataGridViewRow In Datagridview_STK_RPT.Rows ' 跳过新增空行,避免处理未初始化的数据 If row.IsNewRow Then Continue For Dim dr As DataRow = dt.NewRow() For Each column As DataGridViewColumn In Datagridview_STK_RPT.Columns Dim cellValue = row.Cells(column.Name).Value If cellValue IsNot Nothing Then dr(column.Name) = cellValue.ToString() & vbTab & "|" Else ' 明确赋值为DBNull,避免DataTable列值为空引用 dr(column.Name) = DBNull.Value End If Next dt.Rows.Add(dr) Next Dim filePath As String = "D:\" & ComboBox_branch.Text & ".txt" MsgBox("TEXT " & ComboBox_branch.Text & " CREATED IN D:\") DataTableToTextFile(dt, filePath) End Sub
修改点3:优化DataTableToTextFile中的表头重复逻辑(可选)
原代码分页时固定写死表头,可改为动态读取列名适配slno列:
' 替换原代码中ln >=57时的表头输出行 sw.WriteLine("REGION BRANCH POS_SLNO DAMAGE MISSING") ' 改为: For i As Integer = 0 To dt.Columns.Count - 1 sw.Write(dt.Columns(i).ColumnName.PadRight(maxLengths(i) + 3)) Next sw.WriteLine()
修改后即可保留slno列并正常导出数据,解决空引用错误。
内容的提问来源于stack exchange,提问作者siva johney
相关产品推荐
相关产品推荐

