让用户输入并为已绑定的组合框添加值

时间:2016-12-21 20:27:46

标签: vb.net combobox

我的应用程序中有一个组合框,其中包含来自SQL SERVER的十几个项目。我目前正在尝试允许用户能够在组合框中键入新值并将其保存到SQL SERVER中的表中。我正在寻找DropDown和DropDownList的DropDownStyle的东西。基本上我希望让用户键入组合框,但是如果值不存在,我希望能够给他们一个保存它的选项(可能是丢失焦点)。我想知道做这样的事情的好方法。

在失去焦点时,我应该基本上查看当前在下拉菜单中的每个项目,并根据输入的值检查它吗?

编辑:

    Sql="SELECT IDvalue, TextName from TblReference"
    Dim objconn As New SqlConnection
    objconn = New SqlConnection(conn)
    objconn.Open()

    Dim da As New SqlDataAdapter(sql, objconn)
    Dim ds As New DataSet

    da.Fill(ds, "Name")

    If ds.Tables("Name").Rows.Count > 0 Then
    Dim dr As DataRow = ds.Tables("Name ").NewRow
    ds.Tables("Name").Rows.InsertAt(dr, 0)
    With c
         .DataSource = ds.Tables("Name")
         .ValueMember = " IDvalue "
         .DisplayMember = " TextName "
    End With
    End If

3 个答案:

答案 0 :(得分:1)

我这样做的方法是在窗口加载时执行新的SQL查询以获取表中的值列表,并将它们加载到组合框中。

然后,一旦焦点丢失,它就会根据已加载的当前值检查当前键入组合框的内容。如果它不存在,那么它不在SQL中。像下面这样......

    Dim found As Boolean = False

    For i As Integer = 0 To comboBox.Items.Count - 1
        Dim value As String = comboBox.Items(i).ToString()
        If comboBox.Text = value Then
            found = True
        End If
    Next

    If found = False Then
        'the item doesn't exist.. add it to SQL
    Else
        'the item exists.. no need to touch SQL
    End If

答案 1 :(得分:1)

我要做的第一件事就是建立一个简单的类来通过这个类的List

来保存你的值
Public Class DataItem
   Public Property IDValue As Integer
   Public Property TextName as String
End Class

现在,不是构建SqlDataAdapter并填充数据集,而是使用SqlDataReader并构建List(Of DataItem)

' Class global...
Dim allItems = new List(Of DataItem)()

Sql="SELECT IDvalue, TextName from TblReference"

' Using to avoid leaks on disposable objects
Using objconn As New SqlConnection(conn)
Using cmd As New SqlCommand(Sql, objconn)
    objconn.Open()
    Using reader = cmd.ExecuteReader()
       While reader.Read()
          Dim item = new DataItem() With { .IDValue = reader.GetInt32(0), .TextName = reader.GetString(1)}
          allItems.Add(item)
       End While
    End Using
    if allItems.Count > 0 Then
       allItems.Insert(0, new DataItem() With {.IDValue = -1, .TextValue = ""}
       Dim bs = new BindingList(Of DataItem)(allItems)
       c.DataSource = bs 
       c.ValueMember = "IDvalue"
       c.DisplayMember = "TextName"
    End If
End Using
End Using

现在要添加到组合框的Leave事件的代码

Sub c_Leave(sender As Object, e As EventArgs) Handles c.Leave
    If Not String.IsNullOrEmpty(c.Text) Then
        Dim bs = DirectCast(c.DataSource, BindingList(Of DataItem))
        if bs.FirstOrDefault(Function(x) x.TextName = c.Text) Is Nothing Then
            Dim item = new DataItem() With { .IDValue = -1, .TextName = c.Text}
            bs.Add(item)

            ' here add the code to insert in the database
        End If
    End If
End Sub

答案 2 :(得分:1)

您已经在表格中添加了假/空行,您可以为新项目执行相同操作。

' form level datatable var
Private cboeDT As DataTable

初​​始化:

cboeDT = New DataTable

Dim sql = "SELECT Id, Descr FROM TABLENAME ORDER BY Descr"
Using dbcon As New MySqlConnection(MySQLConnStr)
    Using cmd As New MySqlCommand(sql, dbcon)
        dbcon.Open()

        cboeDT.Load(cmd.ExecuteReader())

        ' probably always need this even
        ' when there are no table rows (???)
        Dim dr = cboeDT.NewRow
        dr("Id") = -1       ' need a way to identify it
        dr("Descr") = ""
        cboeDT.Rows.InsertAt(dr, 0)
    End Using
End Using

cboeDT.DefaultView.Sort = "Descr ASC"

cboE.DataSource = cboeDT
cboE.DisplayMember = "Descr"
cboE.ValueMember = "Id"

注意用户倾向于优先考虑这些事情的顺序。这些简单的生物往往更倾向于按字母顺序排列,而不是数字标识。为了适应它们,DefaultView被排序,以便添加的任何新行将以正确的顺序显示。

在离开事件中添加新项目(非常像史蒂夫')

Private Sub cboE_Leave(sender ...
    ' if it is new, there will be no value
    If cboE.SelectedValue Is Nothing Then
        ' alternatively, search for the text:
        'Dim item = cboeDT.AsEnumerable().
        '    FirstOrDefault(Function(q) String.Compare(q.Field(Of String)("Descr"),
        '                                                            cboE.Text, True) = 0)
        'If item Is Nothing Then 
        '    ' its new...

        Dim newid = AddNewItem(cboE.Text)

        Dim dr = cboeDT.NewRow
        dr("Id") = newid
        dr("Descr") = cboE.Text
        cboeDT.Rows.Add(dr)

        ' fiddling with the DS looses the selection,
        '    put it back
        cboE.SelectedValue = newid
    End If
End Sub

如果您想按文字搜索:

Dim item = cboeDT.AsEnumerable().
    FirstOrDefault(Function(q) String.Compare(q.Field(Of String)("Descr"),
                                                            cboE.Text, True) = 0)
If item Is Nothing Then
    ' its new...
    ...

根据实际的数据库,插入会有所不同。但关键的一步是捕获并返回新项目的ID,因为CBO需要它:

Private Function AddNewItem(newItem As String) As Int32

    Dim sql = "INSERT INTO MY_TABLE (Descr) VALUES (@v); SELECT LAST_INSERT_ID();"
    Dim newId = -1
    Using dbcon As New MySqlConnection(MySQLConnStr)
        Using cmd As New MySqlCommand(sql, dbcon)
            dbcon.Open()

            cmd.Parameters.Add("@v", MySqlDbType.String).Value = newItem

            ' MySql provides it in the command object
            If cmd.ExecuteNonQuery() = 1 Then
                newId = Convert.ToInt32(cmd.LastInsertedId)
            End If
        End Using
    End Using

    Return newId
End Function

如上所述,MySql提供LastInsertedID作为命令对象属性。在SQL SERVER中,将...";SELECT LAST_INSERT_ID();"添加到SQL的末尾,然后:

newId = Convert.ToInt32(cmd.ExecuteScalar())

这在概念上与史蒂夫的回答没有什么不同,除了它使用你构建的DataTable而不是使它(非常)稍微简单的集合。