必须在使用 DataView 之前设置 DataTable。我是否以错误的方式绑定数据?

DataTable must be set prior to using DataView. Am I binding my data the wrong way?

我开始这个项目已经一周了,但我完全不知道要修复什么。下面是我的编码的一部分。

Protected Sub bpn_Click(sender As Object, e As EventArgs)
    Try
      Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("SQLServer2005DBConnectionString").ToString())
        connection.Open()
        Dim sql As String = ("select * from LOT_ WHERE PRODUCTNAME ='" & txtbpn.Text & "'")
        Dim cmd As SqlCommand = New SqlCommand(sql, connection)
        Using reader As SqlDataReader = cmd.ExecuteReader
            If reader.HasRows Then
                lblerror.Visible = False
                connection.Dispose()
                connection.Close()
                Me.BindBpn()

                txtbpn.Text = String.Empty
                TextBox2.Text = String.Empty
                TextBox3.Text = String.Empty
                TextBox4.Text = String.Empty
                TextBox5.Text = String.Empty
            Else
                connection.Dispose()
                connection.Close()

                lblerror.Text = "bpn not found"
                lblerror.Visible = True
                txtbpn.Text = String.Empty
                TextBox2.Text = String.Empty
                TextBox3.Text = String.Empty
                TextBox4.Text = String.Empty
                TextBox5.Text = String.Empty
            End If
        End Using
    Catch ex As Exception
        Response.Write(ex.Message)
        Response.AppendHeader("Refresh", "1;url=Summary.aspx")
    End Try
End Sub

1.the绑定子

    Private Sub BindBpn()

  Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("SQLServer2005DBConnectionString").ToString())
        Using cmd As New SqlCommand("SELECT * FROM LOT_ WHERE PRODUCTNAME='" & txtbpn.Text & "'order by checkin asc")
            Using sda As New SqlDataAdapter()
                con.Open()
                cmd.Connection = con
                sda.SelectCommand = cmd
                Dim dt As New DataTable()
                sda.Fill(dt)
                Dim dv As New DataView(dt)

                GridView1.DataSource = dv
                GridView1.DataBind()
                ' Me.BindGridView()
                con.Close()

            End Using
        End Using
    End Using
    If GridView1.Visible = False Then
        GridView1.Visible = True
    End If
    If Button1.Visible = False Then
        Button1.Visible = True
    End If
End Sub

2.the 尝试对数据进行排序时发生错误。

Protected Sub SortRecords(sender As Object, e As GridViewSortEventArgs)

    Dim SortDir As String = String.Empty
    Dim sortExpression As String = e.SortExpression


    Dim dv As New DataView(GridView1.DataSource) 
    If dv IsNot Nothing Then
        If direction = SortDirection.Ascending Then
            direction = SortDirection.Descending

            SortDir = "Desc"
            ViewState("SortExpression") = Convert.ToString(e.SortExpression & " " & SortDir)
        Else
            direction = SortDirection.Ascending

            SortDir = "Asc"
            ViewState("SortExpression") = Convert.ToString(e.SortExpression & " " & SortDir)

        End If


    End If

    dv.Sort = ViewState("SortExpression").ToString 
    GridView1.DataSource = dv
    GridView1.DataBind()
end sub

错误发生在这段代码上

dv.Sort = ViewState("SortExpression").ToString 

任何帮助都会很棒。提前致谢

这是我的 aspx GridView:

  <asp:GridView ID="GridView1" width="100%" runat="server" 
              AllowSorting="True" 
              OnSorting="SortRecords"  
              OnRowDataBound="GridView1_RowDataBound"   
              ItemStyle-HorizontalAlign="Center" 
              AutoGenerateColumns="False" >
    <Columns>
      <asp:TemplateField HeaderText="ID"  ItemStyle-HorizontalAlign="Center">
        <ItemTemplate>
          <%# Container.DataItemIndex + 1 %>
        </ItemTemplate>
        <ItemStyle HorizontalAlign="center" Width="5%" />
      </asp:TemplateField>

      <asp:BoundField DataField="Location" HeaderText="Location" />
      <asp:BoundField DataField="LOT_ID" HeaderText="Lot ID"  />
      <asp:BoundField DataField="PkgName" HeaderText="PIN PACKAGE NAME" />
      <asp:BoundField DataField="MBTBoardNo" HeaderText="MBTBoardNo" SortExpression="MBTBoardNo" />
      <asp:BoundField DataField="BTProgramName" HeaderText="BT Program Name"  />
      <asp:BoundField DataField="ProductRank" HeaderText="ProdRank"/>
      <asp:BoundField DataField="BASEPRODUCTNAME" HeaderText="BPN" />
      <asp:BoundField DataField="MCNo" HeaderText="MC No" />
      <asp:BoundField DataField="QTY" HeaderText="Qty" />
      <asp:BoundField DataField="CreateDate" HeaderText="Start Date" />
      <asp:BoundField DataField="CheckIn" HeaderText="CheckIn" />
      <asp:BoundField DataField="CheckOut" HeaderText="CheckOut" />  
    </Columns>
  </asp:GridView>

这可能有点矫枉过正,但我​​需要解释一些事情。

Sql 抛开注入攻击,目前您还有很多其他事情需要先了解。

  1. 您在排序时遇到问题,因为您没有将检索到的数据缓存到任何持久性机制。您的排序机制中的此代码将始终评估为 Nothing:

    Dim dv As New DataView(GridView1.DataSource)

  2. GridView DataSource 不会跨 postbacks 持久化,除非你 使用像 SqlDataSource 这样的缓存数据控件来管理 缓存给你。

  3. 或者您以编程方式执行以下操作之一:

    1. ViewState(坏主意)
    2. SessionState(不完美)
    3. 应用程序缓存(理想)

但回到基础:

这是您的post第一部分的编辑和注释版本 我将提供一个清理后的版本:

Protected Sub bpn_Click(sender As Object, e As EventArgs)
  ' Added for clarity
  Dim cs as String = ConfigurationManager.ConnectionStrings("SQLServer2005DBConnectionString").ToString()
  ' Try is generally not needed if you are using Using
  ' at least not here. Move it to the inner most Using block and 
  ' wrap it around the actual command execution to catch sql errors
  ' you want to personally manage.

  ' Try   

  Using connection As New SqlConnection(cs)
      connection.Open()
     ' String.Format() - learn to love this function 
     Dim sql As String = String.Format("select * from LOT WHERE PRODUCTNAME ='{0}' order by checkin asc", txtbpn.Text)

     Dim cmd As SqlCommand = New SqlCommand(sql, connection)

       ' This reader is not necessary as all you are doing 
       ' is using it to determine if there is anything to do
       ' This is a waste of time
       ' You already have one open connection and 
       ' now you are jumping to a bind operation 
       ' that opens more. 
       ' Generally speaking: 
       '   open a data connection, get the data, close the connection
       Using reader As SqlDataReader = cmd.ExecuteReader

         ' Do this here, not in both parts of the `If`
         lblerror.Visible = reader.HasRows

         ' lblerror.Text can be initialized here or in the .aspx 
         ' as you do nothing else with it but toggle its visibility
         ' Plus you can make use of a GridView's EmptyDataText property
         ' and get rid of the Label altogether.
         lblerror.Text = "bpn not found"

         If reader.HasRows Then

             Me.BindBpn() 

         End If

         ' This code is not needed as it's handled by the outer Using
         ' connection.Dispose()
         ' connection.Close()

         // Since this code happens in both parts of the 
         // IF, it only needs to happen once.
         txtbpn.Text = String.Empty
         TextBox2.Text = String.Empty
         TextBox3.Text = String.Empty
         TextBox4.Text = String.Empty
         TextBox5.Text = String.Empty

      // Check your original code: 2 Using requires 2 End Using  
      End Using
    End Using
  ' See Try above
  Catch ex As Exception
      Response.Write(ex.Message)

      'Why are you trying to refresh every second?
      Response.AppendHeader("Refresh", "1;url=Summary.aspx")
  End Try
End Sub

这是没有所有注释的修订代码

Protected Sub bpn_Click(sender As Object, e As EventArgs)
  Dim cs as String = ConfigurationManager.ConnectionStrings("SQLServer2005DBConnectionString").ToString()
  Using connection As New SqlConnection(cs)
     connection.Open()
     Dim sql As String = String.Format("select * from LOT WHERE PRODUCTNAME ='{0}' order by checkin asc", txtbpn.Text)

     Dim cmd As SqlCommand = New SqlCommand(sql, connection)

     Using sda As New SqlDataAdapter( cmd )
        Try
          Dim dt As New DataTable()
          sda.Fill(dt)
          Dim dv as New DataView(dt)

          ' This will persist the retrieved record set
          ' -- Replaced C# syntax with VB 
          Cache("AStringToIdentifyThisGridviewCache") = dv
          GridView1.DataSource = Cache("AStringToIdentifyThisGridviewCache")

          Gridview1.EmptyDataText = "bpn not found"
          GridView1.DataBind()
          GridView1.Visible = (GridView1.Rows.Count > 0)

          txtbpn.Text = String.Empty
          TextBox2.Text = String.Empty
          TextBox3.Text = String.Empty
          TextBox4.Text = String.Empty
          TextBox5.Text = String.Empty

        Catch ex As Exception
          Gridview1.EmptyDataText = ex.Message
        End Try

     End Using
    End Using
End Sub

还有一件事,您的数据将从数据库中检索,并且会在您每次点击按钮时覆盖缓存并重新绑定到 GridView。

通常,您希望检索数据一次,然后使用缓存数据集,直到数据以某种方式修改,需要再次访问数据库。

程序化数据检索和绑定当然有用,但我发现我很少需要使用它。您可能需要满足此项目的要求,但对于 GridView 操作,很难击败提供的数据源控件。

希望这对您有所帮助。 快乐编码。

从用于 GridView 排序的 MSDN 示例中提取的排序代码

  Protected Sub SortRecords(ByVal sender As Object, ByVal e As GridViewSortEventArgs)

    'Retrieve the table from the session object.
    Dim dv As DataView = TryCast(Cache("AStringToIdentifyThisGridviewCache"), DataView)

    If dv IsNot Nothing Then
        'Sort the data.
        dv.Sort = e.SortExpression & " " & GetSortDirection(e.SortExpression)
        GridView1.DataSource = Cache("AStringToIdentifyThisGridviewCache")
        GridView1.DataBind()

    End If

  End Sub


  Private Function GetSortDirection(ByVal column As String) As String

    ' By default, set the sort direction to ascending.
    Dim sortDirection = "ASC"

    ' Retrieve the last column that was sorted.
    Dim sortExpression = TryCast(ViewState("SortExpression"), String)

    If sortExpression IsNot Nothing Then
        ' Check if the same column is being sorted.
        ' Otherwise, the default value can be returned.
        If sortExpression = column Then
            Dim lastDirection = TryCast(ViewState("SortDirection"), String)
            If lastDirection IsNot Nothing _
              AndAlso lastDirection = "ASC" Then

                sortDirection = "DESC"

            End If
        End If
    End If

    ' Save new values in ViewState.
    ViewState("SortDirection") = sortDirection
    ViewState("SortExpression") = column

    Return sortDirection

  End Function