0

Summary:

I want to check the current ComboBox.text value against the list of items in a ComboBox that is assigned a DataSource at run time. If the text doesn't match an item in the list then it will select the first item in the list.


Here is what I originally tried:

' This Load function is just here to give an example of how I bound the ComboBox '
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    Me.myComboBox.DisplayMember = "something"
    Me.myComboBox.ValueMember = "otherthing"
    Me.myComboBox.DataSource = Me.myDataTable
End Sub

' This function is copy/pasted directly out of my code '
Private Sub myComboBox_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles myComboBox.Validating
    If Not DirectCast(sender, ComboBox).Items.Contains(DirectCast(sender, ComboBox).Text) Then
        DirectCast(sender, ComboBox).SelectedValue = -1
    End If
End Sub

However the above code does not work as expected because when inspecting the myComboBox.Items property at run time, it is actually a collection of System.Data.DataRowView objects. So basically it is comparing a String to DataRowView.ToString() which is always false unless the myComboBox.Text value is in fact "System.Data.DataRowView"...


So I thought

"Hey, lets make an extension method to search all the items of the DataViewRow and see if my requested value is in there!", but it's not going as planned...

<Extension()>  
Private Function Contains_databound(ByVal items As ComboBox.ObjectCollection, ByVal value As Object) As Boolean
    Dim Success As Boolean = False

    For Each itm In items
        Dim item As DataRowView = Nothing

        Try
            item = DirectCast(itm, DataRowView)
        Catch ex As Exception
            Throw New Exception("Attempted to use a Contains_databound method on a non databound object", New Exception(ex.Message))
        End Try

        If Not IsNothing(item) Then
            For Each rowItem In item.Row.ItemArray
                Dim v1 As String = TryCast(rowItem, String)
                Dim v2 As String = TryCast(value, String)

                If Not IsNothing(v1) And Not IsNothing(v2) Then
                    If v1.Equals(v2) Then
                        Success = True
                    End If
                End If
            Next
        End If
    Next
    Return Success
End Function

I know that looks weird, but the code prettify won't work right if the <Extension()> part isn't separated. When I attempt to use my extension method in my main code, I get an error about my extension method not being a member of ComboBox.ObjectCollection which seems bogus to me because in the extension method I am specifically saying that the first parameter is a ComboBox.ObjectCollection.

Private Sub myComboBox_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles myComboBox.Validating
    If DirectCast(sender, ComboBox).Items.Contains_databound(DirectCast(sender, ComboBox).Text) Then
        DirectCast(sender, ComboBox).SelectedValue = -1
    End If
End Sub

Infamous "HOW TO BRAIN SURGERY WITH POTATO" request...

How can I determine that the text a user inputs into a databound ComboBox is in the list of items from the DataSource?

Side note: C# answers are fine so long as they have a VB.NET counterpart

4

2 回答 2

1

您实际上要确定的是任何项目的显示文本是否与其他值匹配。获取您调用的项目的显示文本GetItemText。我会发布一个例子。

这是一个可以完成这项工作的扩展方法:

Imports System.Runtime.CompilerServices

Public Module ComboBoxExtensions

    <Extension>
    Public Function ContainsItemText(source As ComboBox, itemText As String) As Boolean
        Return source.Items.Cast(Of Object).Any(Function(item) source.GetItemText(item) = itemText)
    End Function

End Module
于 2014-09-03T02:45:41.477 回答
1

我认为以下代码代表了您所描述的内容。基本上看btn.Clicked事件代码。

public class FormAB : Form {

    ComboBox combo = new ComboBox { DropDownStyle = ComboBoxStyle.DropDown, Dock = DockStyle.Top };
    Button btn = new Button { Text = "Button", Dock = DockStyle.Top };

    public FormAB() {
        Controls.Add(btn);
        Controls.Add(combo);

        DataTable table = new DataTable();
        table.Columns.Add("FirstName");
        table.Columns.Add("BirthDate", typeof(DateTime));

        table.Rows.Add("Alan", DateTime.Today.AddYears(-20));
        table.Rows.Add("Bob", DateTime.Today.AddYears(-35));

        combo.DataSource = table;
        combo.DisplayMember = "FirstName";
        combo.ValueMember = "FirstName";

        btn.Click += delegate {
            Object rv = combo.Items.Cast<Object>().Where(r => combo.GetItemText(r) == "Bob").FirstOrDefault();
            // either/or
            //Object rv = combo.Items.Cast<DataRowView>().Where(r => (String) r[combo.DisplayMember] == "Bob").FirstOrDefault();
            if (rv == null && combo.Items.Count > 0)
                rv = combo.Items[0];
            combo.SelectedItem = rv;
        };
    }
}
于 2014-09-03T02:58:30.373 回答