无法将行添加到没有列的DataGridView控件中。必须先添加列。在vb.net中

发布于 2025-02-04 17:22:44 字数 949 浏览 4 评论 0原文

我在我的VB.NET代码中遇到了一个错误,上面写着:“没有行可以添加到没有列的DataGridView控件中。必须先添加列。”。当我尝试在DataGridView1上进行实时搜索时。请帮我。

这是遇到错误的DataGrid实时搜索的代码:

Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
    DataGridView1.Rows.Clear()
    '' Searching via room number or category id, ie room type
    Try
        conn.Open()
        Dim cmd As New MySqlCommand("SELECT r.id, r.room_no, c.name, r.description, r.price FROM categories c JOIN rooms r ON c.id = r.category_id WHERE room_no LIKE '%" & txt_search.Text & "%' or name LIKE '%" & txt_search.Text & "%'", conn)
        dr = cmd.ExecuteReader
        While dr.Read
            DataGridView1.Rows.Add(dr.Item("ID"), dr.Item("room_no"), dr.Item("name"), dr.Item("description"), dr.Item("price"))
        End While
        dr.Dispose()
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    conn.Close()
End Sub

I have been encountering an error in my VB.Net code that says "No row can be added to a DataGridView control that does not have columns. Columns must be added first.". When I was trying to code a live search on a datagridview1. Please help me.

Here is the code for the datagrid live search that encounters an error:

Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
    DataGridView1.Rows.Clear()
    '' Searching via room number or category id, ie room type
    Try
        conn.Open()
        Dim cmd As New MySqlCommand("SELECT r.id, r.room_no, c.name, r.description, r.price FROM categories c JOIN rooms r ON c.id = r.category_id WHERE room_no LIKE '%" & txt_search.Text & "%' or name LIKE '%" & txt_search.Text & "%'", conn)
        dr = cmd.ExecuteReader
        While dr.Read
            DataGridView1.Rows.Add(dr.Item("ID"), dr.Item("room_no"), dr.Item("name"), dr.Item("description"), dr.Item("price"))
        End While
        dr.Dispose()
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    conn.Close()
End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沉溺在你眼里的海 2025-02-11 17:22:44

我会做一些不同的事情。

  1. 您不应在班级级别声明您的连接,而应创建一个新的连接并在完成后立即处置。
  2. 与datarow相同。
  3. 我个人不想在搜索框中键入字符后立即看到结果。如果我有错别字,那么要删除并修复它,我需要等待错别字结果,然后查看固定结果。我们将使用计时器来创建此延迟。
  4. 这将我带到了另一个问题,也就是说,您要在UI线程上击中数据库,因此将其添加到最后一个项目中,您的最终用户在等待每一个的结果时都会遇到a ui freeze 按键。我们将在UI上查询,并在完成后调用更新。
  5. 不要将文本框文本直接放入查询中,否则您将被开放到SQL注入问题。我们将使用参数

(哦,我什至还没有提出您的问题!)

  1. 您可以简单地将结果数据作为网格数据,而不是尝试添加行。您只能在网格具有预定义的行带有新行模板的预定义行时添加行。您可以做到这一点,但这将UI锁定到特定的设计中,因此,如果您以后要更改查询,也需要修复UI。太紧了。我们将使用类定义数据。如果您使用的ORM优于使用DataReader,但是您不这样做,那么您将获得这些。

让我们看看...

Private Class Result
    Public Sub New(iD As Integer, room_no As String, name As String, description As String, price As Decimal)
        Me.ID = iD
        Me.Room_no = room_no
        Me.Name = name
        Me.Description = description
        Me.Price = price
    End Sub
    ' Update data types according to your actual database types
    Public Property ID As Integer
    Public Property Room_no As String
    Public Property Name As String
    Public Property Description As String
    Public Property Price As Decimal
End Class

当您想点击数据库时,您将需要制作一个计时器。还记录此时文本框的当前状态。这是您在文本变化事件处理程序中所做的一切,

Private queryTimer As New System.Threading.Timer(AddressOf queryCallback)
Private queryTerm As String

Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
    queryTerm = txt_search.Text.Trim() ' do you want to trim whitespace?
    ' Execute search 500ms later.
    ' If multiple keystrokes are pressed quickly,
    ' previous timer schedules are cancelled and only the last happens.
    queryTimer.Change(500, -1)
End Sub

这是计时器回调,该计时器回调在完成后运行并调用UI更新

Private Sub queryCallback(state As Object)
    ' This routine is called on a background thread, off the UI
    Dim results As New List(Of Result)()
    Using conn As New MySqlConnection("connection string")
        conn.Open()
        ' build command with parameter
        Using cmd As New MySqlCommand(
$"SELECT r.id, r.room_no, c.name, r.description, r.price 
FROM categories c 
JOIN rooms r ON c.id = r.category_id 
WHERE room_no LIKE '%@search%' 
or name LIKE '%@search%'", conn)
            cmd.Parameters.AddWithValue("@search", queryTerm)
            Using dr = cmd.ExecuteReader()
                While dr.Read()
                    ' Update conversions according to actual data types
                    ' here as well as in the class I provided.
                    results.Add(New Result(
                                Convert.ToInt32(dr("id")),
                                dr("room_no").ToString(),
                                dr("name").ToString(),
                                dr("description").ToString(),
                                Convert.ToDecimal(dr("price"))))
                End While
            End Using
        End Using
    End Using
    ' Can't update the UI from a background thread, so this call is invoked
    DataGridView1.Invoke(
        Sub()
            DataGridView1.DataSource = Nothing
            DataGridView1.DataSource = results
        End Sub)
End Sub

I would do a few things differently.

  1. You should not declare your connection at the class level, instead create a new connection and dispose immediately when done.
  2. Same with the DataRow.
  3. I personally wouldn't like to see results immediately after typing a character in a searchbox. If I have a typo, then want to erase it and fix it, I need to wait for the typo result, then see the fixed result. We'll use a timer to create this delay.
  4. Which brings me to the other issue, which is that you are hitting your database on the UI thread, so add that to the last item, your end user is experiencing a UI freeze while waiting for results with each keypress. We will query off the UI and invoke the update back when done.
  5. Don't put textbox Text directly into a query or you will be opened up to sql injection issues. We will use parameters

(Oh, and I haven't even arrived at your question yet!)

  1. You can simply databind the result to the grid instead of trying to add rows. You can only add rows if the grid has predefined rows with a template for new rows. You can do that but this locks your UI into a particular design so if you want to change the query later, you will also need to fix the UI. Too tightly coupled. We'll use a class to define the data. You will get these if you use an ORM which is vastly superior to using a DataReader, but you don't so I made one.

Let's see...

Private Class Result
    Public Sub New(iD As Integer, room_no As String, name As String, description As String, price As Decimal)
        Me.ID = iD
        Me.Room_no = room_no
        Me.Name = name
        Me.Description = description
        Me.Price = price
    End Sub
    ' Update data types according to your actual database types
    Public Property ID As Integer
    Public Property Room_no As String
    Public Property Name As String
    Public Property Description As String
    Public Property Price As Decimal
End Class

You will want to make a timer to tick when you want to hit the database. Also record the current state of the textbox at this time. This is all you do in the TextChanged event handler

Private queryTimer As New System.Threading.Timer(AddressOf queryCallback)
Private queryTerm As String

Private Sub txt_search_TextChanged(sender As Object, e As EventArgs) Handles txt_search.TextChanged
    queryTerm = txt_search.Text.Trim() ' do you want to trim whitespace?
    ' Execute search 500ms later.
    ' If multiple keystrokes are pressed quickly,
    ' previous timer schedules are cancelled and only the last happens.
    queryTimer.Change(500, -1)
End Sub

This is the timer callback, which runs off the UI and invokes the UI update when it's done

Private Sub queryCallback(state As Object)
    ' This routine is called on a background thread, off the UI
    Dim results As New List(Of Result)()
    Using conn As New MySqlConnection("connection string")
        conn.Open()
        ' build command with parameter
        Using cmd As New MySqlCommand(
quot;SELECT r.id, r.room_no, c.name, r.description, r.price 
FROM categories c 
JOIN rooms r ON c.id = r.category_id 
WHERE room_no LIKE '%@search%' 
or name LIKE '%@search%'", conn)
            cmd.Parameters.AddWithValue("@search", queryTerm)
            Using dr = cmd.ExecuteReader()
                While dr.Read()
                    ' Update conversions according to actual data types
                    ' here as well as in the class I provided.
                    results.Add(New Result(
                                Convert.ToInt32(dr("id")),
                                dr("room_no").ToString(),
                                dr("name").ToString(),
                                dr("description").ToString(),
                                Convert.ToDecimal(dr("price"))))
                End While
            End Using
        End Using
    End Using
    ' Can't update the UI from a background thread, so this call is invoked
    DataGridView1.Invoke(
        Sub()
            DataGridView1.DataSource = Nothing
            DataGridView1.DataSource = results
        End Sub)
End Sub

Additional information is in remarks in the code provided

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文