【问题标题】:How to populate master detail combobox in VB?如何在 VB 中填充主详细信息组合框?
【发布时间】:2020-06-28 11:43:07
【问题描述】:

我有两个 组合框,其中包含主从关系表 BankBranch

我背后的VB代码:-

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        
        Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\New\Test.accdb")



            Using cmd As New OleDbCommand("Select Bank, ID from Bank", con)
                Dim da As New OleDbDataAdapter(cmd)
                Dim dt As New DataTable

                da.Fill(dt)


                ComboBox1.DataSource = dt

                ComboBox1.DisplayMember = "Bank"
                ComboBox1.ValueMember = "ID"
                ComboBox1.Text = "Select"
            End Using
        End Using
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        Dim bankId = ComboBox1.SelectedValue.ToString
        Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\New\Test.accdb")
            Using branch_cmd As New OleDbCommand("Select Branch from Branch where Bank_id ='" & bankId & "'", con)
                Dim da As New OleDbDataAdapter(branch_cmd)
                Dim dt As New DataTable
                da.Fill(dt)
                ComboBox2.DataSource = dt
                ComboBox2.DisplayMember = "Bank"
                ComboBox2.ValueMember = "ID"
            End Using
        End Using
    End Sub
End Class

我想根据第一个组合框选择的值填充第二个组合框,但代码出错 ComboBox1_SelectedIndexChanged 函数:

而且,从调试 branch_cmd sql 是:

Select Branch from Branch where Bank_id ='System.Data.DataRowView'

【问题讨论】:

  • 数据库表Branch上的Bank_id的数据类型是什么?
  • 号码,我用的是Access DB

标签: vb.net combobox


【解决方案1】:

编辑:

我正要添加一个注释,然后我意识到这个注释实际上是您实际问题的解决方案。您首先设置DataSource,然后设置DisplayMemberValueMember。那是错误的,也是您问题的原因。当您设置DataSource 时,您已经完成了绑定,所以一切都会发生。选择列表中的第一项,以便执行您的 SelectedIndexChanged 处理程序。您尚未设置 DisplayMemberValueMember,因此 SelectedValue 不会返回适当的值。总是最后设置DataSource,就像我在下面的示例中所做的那样。

原文:

除非您有大量数据,否则您应该预先从两个表中获取所有数据,绑定数据,然后让绑定自动处理过滤。您可以使用BindingSources 将孩子绑定到DataRelation 而不是DataTable。看!

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim parentTable = GetParentTable()
    Dim childTable = GetChildTable()

    Dim data As New DataSet

    'Create a foreign key relation between the tables.
    data.Tables.Add(parentTable)
    data.Tables.Add(childTable)
    data.Relations.Add("ParentChild", parentTable.Columns("ParentId"), childTable.Columns("ParentId"))

    'Bind the parent BindingSource to the parent table.
    parentBindingSource.DataMember = "Parent"
    parentBindingSource.DataSource = data

    'Bind the child BindingSource to the relation.
    childBindingSource.DataMember = "ParentChild"
    childBindingSource.DataSource = parentBindingSource

    parentComboBox.DisplayMember = "ParentName"
    parentComboBox.ValueMember = "ParentId"
    parentComboBox.DataSource = parentBindingSource

    childComboBox.DisplayMember = "ChildName"
    childComboBox.ValueMember = "ChildId"
    childComboBox.DataSource = childBindingSource
End Sub

Private Function GetParentTable() As DataTable
    Dim table As New DataTable("Parent")

    table.PrimaryKey = {table.Columns.Add("ParentId", GetType(Integer))}
    table.Columns.Add("ParentName", GetType(String))

    table.Rows.Add(1, "Parent 1")
    table.Rows.Add(2, "Parent 2")
    table.Rows.Add(3, "Parent 3")

    Return table
End Function

Private Function GetChildTable() As DataTable
    Dim table As New DataTable("Child")

    table.PrimaryKey = {table.Columns.Add("ChildId", GetType(Integer))}
    table.Columns.Add("ChildName", GetType(String))
    table.Columns.Add("ParentId", GetType(Integer))

    table.Rows.Add(1, "Child 1.1", 1)
    table.Rows.Add(2, "Child 1.2", 1)
    table.Rows.Add(3, "Child 1.3", 1)
    table.Rows.Add(4, "Child 2.1", 2)
    table.Rows.Add(5, "Child 2.2", 2)
    table.Rows.Add(6, "Child 2.3", 2)
    table.Rows.Add(7, "Child 3.1", 3)
    table.Rows.Add(8, "Child 3.2", 3)
    table.Rows.Add(9, "Child 3.3", 3)

    Return table
End Function

如果您这样做,选择父级将自动过滤显示的子级以供选择。

如果不是很明显,您可以通过查询数据库而不是手动构建它们来获取父表和子表,就像我在示例中所做的那样。

【讨论】:

    【解决方案2】:

    就目前而言,我可以看到两个错误。首先,不要连接字符串来构建 sql 命令文本。始终使用参数化查询,准确指定您传递的参数的数据类型。第二个错误出现在第二个组合的 DisplayMember 和 ValueMember 中。您在这里没有 Bank_Id 或银行名称,而是分行名称

    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
    
        ' Always check if you have a valid selection to avoid NRE.  
        if ComboBox1.SelectedValue Is Nothing Then
            Return
        End if
    
        ' If bankid is an integer then convert to an integer
        Dim bankId as Integer = Convert.ToInt32(ComboBox1.SelectedValue)
        Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\New\Test.accdb")
            Using branch_cmd As New OleDbCommand("Select Branch from Branch where Bank_id =@id", con)
                cmd.Parameters.Add("@id", OleDbType.Integer).Value = bankId 
                Dim da As New OleDbDataAdapter(branch_cmd)
                Dim dt As New DataTable
                da.Fill(dt)
                ComboBox2.DataSource = dt
                ComboBox2.DisplayMember = "Branch"
                ComboBox2.ValueMember = "Branch"
            End Using
        End Using
    End Sub
    

    根据您在下面的评论,您将获得一个 System.Data.DataRowView 作为包含在 SelectedValue 中的元素。您的问题中显示的代码不应该发生这种情况,所以也许有一些不同的东西会导致问题。 (例如,如果数据表字段名称与 ValueMember/DisplayMember 属性不匹配)

    无论如何,从 DataRowView 中,您应该能够以这种方式获取整数

    Dim drv = DirectCast(ComboBox1.SelectedValue, DataRowView)
    if drv IsNot Nothing then
       Dim bankid = Convert.ToInt32(drv("ID")) 
       ...
    End if 
    

    【讨论】:

    • in line-> Dim bankId as Integer:无法将“System.Data.DataRowView”类型的对象转换为“System.IConvertible”类型。
    • 这很奇怪。在第一个组合的填充中,您将 ValueMember 设置为 ID 字段,我假设此 id 也是一个数字。所以 SelectedValue 应该是一个整数而不是 DataRowView。似乎第一个组合没有正确设置 displaymember 和 valuemember,但是你不应该看到银行名称,而只是 System.Data.DataRowView 的列表
    • 就像问题中的代码一样,您以错误的顺序设置绑定属性。详情见我的回答。
    猜你喜欢
    • 2011-01-30
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2022-01-09
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多