You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
错误原因分析
  1. ValueType未设置:自动生成的slno列是手动添加的未绑定列,未指定ValueType属性,执行dt.Columns.Add(column.Name, column.ValueType)时,column.ValueType为Nothing,触发空引用错误。
  2. 未处理新增空行:DataGridView默认允许添加新行(AllowUserToAddRows=True),该行的slno列未被RowPostPaint事件赋值,值为Nothing,后续处理易引发异常。
  3. 列类型筛选过严:原代码仅遍历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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:48:10