winforms 如何建议追加一个包含字符串的组合框

jvlzgdj9  于 2023-05-23  发布在  其他
关注(0)|答案(6)|浏览(169)

目标

我想让我的ComboBox项目建议,并追加其项目时,其中包含的东西,而不仅仅是通过StartsWith函数。
我的ComboBox绑定到一个DataView,该DataView包含客户端[CompanyName],[Address],[City],并以长串连接。
我希望我的用户能够在城市类型,仍然找到与上述所有领域相匹配的记录。我知道这是可能的Infragistics,但我没有那个包。
检索词:“嘘……”

  • Costco,123 1st Avenue,Sher布鲁克
  • Provigo,344 Ball Street,谢尔布鲁克

这在VB.Net中可能吗?或者我应该搜索其他东西?

hm2xizp9

hm2xizp91#

ComboBoxTextBox和我认为DropDownList具有AutoComplete属性
它说明了应使用哪种AutoCompleteMode以及如何设置AutoCompleteSource

hc2pp10m

hc2pp10m2#

你可以试试下面的几句话,对我很有效

cbxName.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
 cbxName.AutoCompleteSource = AutoCompleteSource.ListItems;
h6my8fg2

h6my8fg23#

我做了一些研究,发现了以下问题:
Override Winforms ComboBox Autocomplete Suggest Rule
在这个问题中,他们提到了另一个问题:
C# AutoComplete

让我们引用这个问题的最佳答案

现有的自动完成功能仅支持按前缀搜索。似乎没有任何像样的方法来覆盖这种行为。
有些人通过覆盖OnTextChanged事件实现了自己的自动完成功能。这可能是你最好的选择
例如,您可以在TextBox的正下方添加ListBox,并将其默认可见性设置为false。然后,您可以使用TextBoxOnTextChanged事件和ListBoxSelectedIndexChanged事件来显示和选择项目。
这似乎是一个很好的基本示例:

public Form1()
{
    InitializeComponent();

    acsc = new AutoCompleteStringCollection();
    textBox1.AutoCompleteCustomSource = acsc;
    textBox1.AutoCompleteMode = AutoCompleteMode.None;
    textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
}

private void button1_Click(object sender, EventArgs e)
{
    acsc.Add("[001] some kind of item");
    acsc.Add("[002] some other item");
    acsc.Add("[003] an orange");
    acsc.Add("[004] i like pickles");
}

void textBox1_TextChanged(object sender, System.EventArgs e)
{
    listBox1.Items.Clear();
    if (textBox1.Text.Length == 0)
    {
    hideResults();
    return;
    }

    foreach (String s in textBox1.AutoCompleteCustomSource)
    {
    if (s.Contains(textBox1.Text))
    {
        Console.WriteLine("Found text in: " + s);
        listBox1.Items.Add(s);
        listBox1.Visible = true;
    }
    }
}

void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
    textBox1.Text = listBox1.Items[listBox1.SelectedIndex].ToString();
    hideResults();
}

void listBox1_LostFocus(object sender, System.EventArgs e)
{
    hideResults();
}

void hideResults()
{
    listBox1.Visible = false;
}

你可以做很多事情,而不需要太多的努力:向文本框追加文本、捕获其他键盘命令等。

ssm49v7z

ssm49v7z4#

改进了弯曲在他的回答中演示的技术,以便使该机制更优雅地处理某些角落情况:

public sealed class CCComboboxAutocomplete : ComboBox
{
    public CCComboboxAutocomplete()
    {
        AutoCompleteMode = AutoCompleteMode.Suggest; //crucial otherwise exceptions occur when the user types in text which is not found in the autocompletion list
    }

    protected override void OnTextChanged(EventArgs e)
    {
        try
        {
            if (DesignMode || !string.IsNullOrEmpty(Text) || !Visible) return;

            ResetCompletionList();
        }
        finally
        {
            base.OnTextChanged(e);
        }
    }

    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        try
        {
            if (DesignMode) return;
            if (e.KeyChar == '\r' || e.KeyChar == '\n')
            {
                e.Handled = true;
                if (SelectedIndex == -1 && Items.Count > 0 && Items[0].ToString().ToLowerInvariant().StartsWith(Text.ToLowerInvariant()))
                {
                    Text = Items[0].ToString();
                }
                DroppedDown = false;
                return; //0
            }

            BeginInvoke(new Action(ReevaluateCompletionList)); //1
        }
        finally
        {
            base.OnKeyPress(e);
        }
    }
    //0 Guardclose when detecting any enter keypresses to avoid a glitch which was selecting an item by means of down arrow key followed by enter to wipe out the text within
    //1 Its crucial that we use begininvoke because we need the changes to sink into the textfield  Omitting begininvoke would cause the searchterm to lag behind by one character  That is the last character that got typed in

    private void ResetCompletionList()
    {
        _previousSearchterm = null;
        try
        {
            SuspendLayout();

            var originalList = (object[])Tag;
            if (originalList == null)
            {
                Tag = originalList = Items.Cast<object>().ToArray();
            }

            if (Items.Count == originalList.Length) return;

            while (Items.Count > 0)
            {
                Items.RemoveAt(0);
            }

            Items.AddRange(originalList);
        }
        finally
        {
            ResumeLayout(performLayout: true);
        }
    }

    private string _previousSearchterm;
    private void ReevaluateCompletionList()
    {
        var currentSearchterm = Text.ToLowerInvariant();
        if (currentSearchterm == _previousSearchterm) return; //optimization

        _previousSearchterm = currentSearchterm;
        try
        {
            SuspendLayout();

            var originalList = (object[])Tag;
            if (originalList == null)
            {
                Tag = originalList = Items.Cast<object>().ToArray(); //0
            }

            var newList = (object[])null;
            if (string.IsNullOrEmpty(currentSearchterm))
            {
                if (Items.Count == originalList.Length) return;

                newList = originalList;
            }
            else
            {
                newList = originalList.Where(x => x.ToString().ToLowerInvariant().Contains(currentSearchterm)).ToArray();
            }

            try
            {
                while (Items.Count > 0) //1
                {
                    Items.RemoveAt(0);
                }
            }
            catch
            {
                try
                {
                    Items.Clear();
                }
                catch
                {
                }
            }

            Items.AddRange(newList.ToArray()); //2
        }
        finally
        {
            if (currentSearchterm.Length >= 2 && !DroppedDown)
            {
                DroppedDown = true; //3
                Cursor.Current = Cursors.Default; //4
                Text = currentSearchterm; //5
                Select(currentSearchterm.Length, 0);
            }

            ResumeLayout(performLayout: true);
        }
    }
    //0 backup original list
    //1 clear list by loop through it otherwise the cursor would move to the beginning of the textbox
    //2 reset list
    //3 if the current searchterm is empty we leave the dropdown list to whatever state it already had
    //4 workaround for the fact the cursor disappears due to droppeddown=true  This is a known bu.g plaguing combobox which microsoft denies to fix for years now
    //5 Another workaround for a glitch which causes all text to be selected when there is a matching entry which starts with the exact text being typed in
}
dm7nw8vv

dm7nw8vv5#

抱歉,我用C#给出了另一个答案,但我有一个基于xDisruptor代码的更好的答案。
使用kinda行为(装饰器)。
您不必子类化ComboBox并更改designed中的所有现有组合。
使用Datasource而不是Items集合时要小心,因为它会引发异常。
验证码:

public class AutoCompleteBehavior
{
    private readonly ComboBox comboBox;
    private string previousSearchterm;

    private object[] originalList;

    public AutoCompleteBehavior(ComboBox comboBox)
    {
        this.comboBox = comboBox;
        this.comboBox.AutoCompleteMode = AutoCompleteMode.Suggest; // crucial otherwise exceptions occur when the user types in text which is not found in the autocompletion list
        this.comboBox.TextChanged += this.OnTextChanged;
        this.comboBox.KeyPress += this.OnKeyPress;
        this.comboBox.SelectionChangeCommitted += this.OnSelectionChangeCommitted;
    }

    private void OnSelectionChangeCommitted(object sender, EventArgs e)
    {
        if (this.comboBox.SelectedItem == null)
        {
            return;
        }

        var sel = this.comboBox.SelectedItem;
        this.ResetCompletionList();
        this.comboBox.SelectedItem = sel;
    }

    private void OnTextChanged(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(this.comboBox.Text) || !this.comboBox.Visible || !this.comboBox.Enabled)
        {
            return;
        }

        this.ResetCompletionList();
    }

    private void OnKeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == '\r' || e.KeyChar == '\n')
        {
            e.Handled = true;
            if (this.comboBox.SelectedIndex == -1 && this.comboBox.Items.Count > 0
                && this.comboBox.Items[0].ToString().ToLowerInvariant().StartsWith(this.comboBox.Text.ToLowerInvariant()))
            {
                this.comboBox.Text = this.comboBox.Items[0].ToString();
            }

            this.comboBox.DroppedDown = false;

            // Guardclause when detecting any enter keypresses to avoid a glitch which was selecting an item by means of down arrow key followed by enter to wipe out the text within
            return;
        }

        // Its crucial that we use begininvoke because we need the changes to sink into the textfield  Omitting begininvoke would cause the searchterm to lag behind by one character  That is the last character that got typed in
        this.comboBox.BeginInvoke(new Action(this.ReevaluateCompletionList));
    }

    private void ResetCompletionList()
    {
        this.previousSearchterm = null;
        try
        {
            this.comboBox.SuspendLayout();

            if (this.originalList == null)
            {
                this.originalList = this.comboBox.Items.Cast<object>().ToArray();
            }

            if (this.comboBox.Items.Count == this.originalList.Length)
            {
                return;
            }

            while (this.comboBox.Items.Count > 0)
            {
                this.comboBox.Items.RemoveAt(0);
            }

            this.comboBox.Items.AddRange(this.originalList);
        }
        finally
        {
            this.comboBox.ResumeLayout(true);
        }
    }

    private void ReevaluateCompletionList()
    {
        var currentSearchterm = this.comboBox.Text.ToLowerInvariant();
        if (currentSearchterm == this.previousSearchterm)
        {
            return;
        }

        this.previousSearchterm = currentSearchterm;
        try
        {
            this.comboBox.SuspendLayout();

            if (this.originalList == null)
            {
                this.originalList = this.comboBox.Items.Cast<object>().ToArray(); // backup original list
            }

            object[] newList;
            if (string.IsNullOrEmpty(currentSearchterm))
            {
                if (this.comboBox.Items.Count == this.originalList.Length)
                {
                    return;
                }

                newList = this.originalList;
            }
            else
            {
                newList = this.originalList.Where(x => x.ToString().ToLowerInvariant().Contains(currentSearchterm)).ToArray();
            }

            try
            {
                // clear list by loop through it otherwise the cursor would move to the beginning of the textbox
                while (this.comboBox.Items.Count > 0)
                {
                    this.comboBox.Items.RemoveAt(0);
                }
            }
            catch
            {
                try
                {
                    this.comboBox.Items.Clear();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }

            this.comboBox.Items.AddRange(newList.ToArray()); // reset list
        }
        finally
        {
            if (currentSearchterm.Length >= 1 && !this.comboBox.DroppedDown)
            {
                this.comboBox.DroppedDown = true; // if the current searchterm is empty we leave the dropdown list to whatever state it already had
                Cursor.Current = Cursors.Default; // workaround for the fact the cursor disappears due to droppeddown=true  This is a known bu.g plaguing combobox which microsoft denies to fix for years now
                this.comboBox.Text = currentSearchterm; // Another workaround for a glitch which causes all text to be selected when there is a matching entry which starts with the exact text being typed in
                this.comboBox.Select(currentSearchterm.Length, 0);
            }

            this.comboBox.ResumeLayout(true);
        }
    }
}

用途:

new AutoCompleteBehavior(this.comboBoxItems);
this.comboBoxItems.Items.AddRange(new object[] { "John", "Tina", "Doctor", "Alaska" });

提示:可以通过对ComboBox类进行扩展(如myCombo.ToAutoComplete())来进一步改进

qq24tv8q

qq24tv8q6#

我已经解决了:)
对不起,它也是C#,但我认为将其转换为VB.Net非常容易
您需要:
1.有一个普通的组合框(DropDownStyle = DropDown,AutoCompleteMode = None,AutoCompleteSource = None),让我们称之为:comboBox1
1.添加事件***SelectedIndexChanged***和***TextUpdate***
然后使用以下代码:

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace CB_Contains
{
    public partial class Form1 : Form
    {
        private Dictionary<String, System.Int32> CBFullList;
        private Dictionary<String, System.Int32> CBFilteredList;

        bool ComboBoxBusy;

        public Form1()
        {
            InitializeComponent();

            ComboBoxBusy = false;
            CBFullList = new Dictionary<string, Int32>();
            CBFilteredList = new Dictionary<string, Int32>();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            CBFullList.Add("None", 0);
            CBFullList.Add("ABC 123", 1);
            CBFullList.Add("Costco, 123 1st Avenue, Sherbrooke", 2);
            CBFullList.Add("Provigo, 344 Ball Street, Sherbrooke", 3);
            CBFullList.Add("Sherbox, 93 7th Street, Montreal", 4);

            FilterList(false);
        }

        private void FilterList(bool show)
        {
            if (ComboBoxBusy == false)
            {
                String orgText;

                ComboBoxBusy = true;
                orgText = comboBox1.Text;

                comboBox1.DroppedDown = false;

                CBFilteredList.Clear();

                foreach (KeyValuePair<string, Int32> item in CBFullList)
                {
                    if (item.Key.ToUpper().Contains(orgText.ToUpper()))
                        CBFilteredList.Add(item.Key, item.Value);
                }

                if (CBFilteredList.Count < 1)
                    CBFilteredList.Add("None", 0);

                comboBox1.BeginUpdate();
                comboBox1.DataSource = new BindingSource(CBFilteredList, null);
                comboBox1.DisplayMember = "Key";
                comboBox1.ValueMember = "Value";

                comboBox1.DroppedDown = show;
                comboBox1.SelectedIndex = -1;
                comboBox1.Text = orgText;
                comboBox1.Select(comboBox1.Text.Length, 0);
                comboBox1.EndUpdate();
                Cursor.Current = Cursors.Default;

                ComboBoxBusy = false;
            }
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (ComboBoxBusy == false)
            {
                FilterList(false);
            }
        }

        private void comboBox1_TextUpdate(object sender, EventArgs e)
        {
            FilterList(true);
        }
    }
 }

好吧,就是这样:)我希望我的方法很简单

相关问题