Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
690 views
in Technique[技术] by (71.8m points)

winforms - C# Adding Filter to combobox dropdown list

Need some help with adding filter to my ComboBox drop down list(windows Forms Visual studio 2015)

The drop down is populated as per below:

public ReconciliationReport()
{
    InitializeComponent();
    AppDomain.CurrentDomain.AssemblyResolve += FindDLL;

    this.sRootDirectory = Properties.Resources.sRootDirectory;

    string[] arrProjectList = Directory.GetDirectories(sRootDirectory).Select(Directory => Path.GetFileName(Directory)).ToArray();
    Array.Sort(arrProjectList);

    int iProjectCount = arrProjectList.Length;
    this.DropDownListSize = iProjectCount;

    for (int i = 0; i < iProjectCount; i++)
    {
        SelectJobDropdown.Items.Add(arrProjectList[i]);
    }
}

This gives me a nice drop down list of all current directories. enter image description here

Now, I need to add a filer to show only items which contain a text typed into the ComboBoxitself regardless if the dropdown list itself is open or not.

I have disabled both AutoCompleteMode and AutoCompleteSource as it was not working as expected with the opened droped down list. It was opening additonal list on top the existing one but I could only select from the dropdown under it. See print screen below: enter image description here

The list on top is inactive and I cannot select the text but also does not give an option to display substrings.

Only have one even for the box itself which is

private void SelectJobDropdown_SelectedIndexChanged(object sender, EventArgs e) 
{
    //Plenty of code here 
}

Can someone point in the right direction how to filter the list as I type within the box itself.

Please NOTE I have been using C# for only 3 weeks so might get confused with some of the terminology or other aspects of this language etc.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I would suggest to use 2 Lists. 1 for the original values

List<string> arrProjectList;

public ReconciliationReport()
{
    InitializeComponent();
    AppDomain.CurrentDomain.AssemblyResolve += FindDLL;

    this.sRootDirectory = Properties.Resources.sRootDirectory;

    arrProjectList = Directory.GetDirectories(sRootDirectory).Select(Directory => Path.GetFileName(Directory)).ToList();
    arrProjectList.Sort();

    // then just bind it to the DataSource of the ComboBox
    SelectJobDropdown.DataSource = arrProjectList;
    // don't select automatically the first item
    SelectJobDropdown.SelectedIndex = -1;
}

and 1 for the filtered values. In this example I use a TextBox to catch the filter text. In the TextChanged event take the filter text and pull out only those values from the original arrProjectList List. You would need an extra option at the end to reset the binding to the old list if the filter is empty.

private void textBox1_TextChanged(object sender, EventArgs e)
{
    string filter_param = textBox1.Text;

    List<string> filteredItems = arrProjectList.FindAll(x => x.Contains(filter_param));
    // another variant for filtering using StartsWith:
    // List<string> filteredItems = arrProjectList.FindAll(x => x.StartsWith(filter_param));

    comboBox1.DataSource = filteredItems;

    // if all values removed, bind the original full list again
    if (String.IsNullOrWhiteSpace(textBox1.Text))
    {
        comboBox1.DataSource = arrProjectList;
    }

    // this line will make sure, that the ComboBox opens itself to show the filtered results       
}

EDIT

I found a Solution for typing the filter into the ComboBox directly. The filtering is the same procedure, but using the TextUpdate event it is necessary to unselect the SelectedIndex which is automatically set to the first element after the binding. Then I guess you want to proceed to write your filter (more than just one letter), write the filter back into the ComboBox.Text property and set the cursor position to the end:

private void comboBox1_TextUpdate(object sender, EventArgs e)
{
    string filter_param = comboBox1.Text;

    List<string> filteredItems = arrProjectList.FindAll(x => x.Contains(filter_param));
    // another variant for filtering using StartsWith:
    // List<string> filteredItems = arrProjectList.FindAll(x => x.StartsWith(filter_param));

    comboBox1.DataSource = filteredItems;

    if (String.IsNullOrWhiteSpace(filter_param))
    {
        comboBox1.DataSource = arrProjectList;
    }
    comboBox1.DroppedDown = true;

    // this will ensure that the drop down is as long as the list
    comboBox1.IntegralHeight = true;

    // remove automatically selected first item
    comboBox1.SelectedIndex = -1;

    comboBox1.Text = filter_param;

    // set the position of the cursor
    comboBox1.SelectionStart = filter_param.Length;
    comboBox1.SelectionLength = 0;            
}

Et voilà automatic filtering with a nice display and arrow selection afterwards.

EDIT 2

for case insensitive search you can use this:

List<string> filteredItems = arrProjectList.FindAll(x => x.ToLower().Contains(filter_param.ToLower()));

NOTE:

After the opening of the dropdownlist the cursor will disappear. To prevent this the Cursor.Current has to be set to Cursor.Defualt

comboBox1.DroppedDown = true;
Cursor.Current = Cursors.Default;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...