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
323 views
in Technique[技术] by (71.8m points)

c# - ComboBox AutoComplete on SubString

In one of my WinForms applications, I have a window with a ComboBox for the user to select a customer from.

The customers in this list box are in this format : "CustomerID - CustomerName", for example "004540 - NorthWind Traders"

The native WinForms combobox has an autocomplete feature built-in and it works well: the problem is that it only works by matching from the beginning of the string of each item of the combobox's list and not from anywhere (substring).

What I would like my users to be able to do is to either type of the CustomerID or CustomerName, as senior users are familiar with most CustomerIDs while new recruits would benefit from being able to type the CustomerName in and get the AutoComplete anyway. That means that I actually want to look for the best match from the list where the inputted text is a substring of the ComboBox item.

A solution often suggested for this kind of scenario is to create a hidden list box that only shows up when the user types, but I'm not happy with that as it feels like a quick hack and is not easily reusable, and may look and behave inconsistently compared to the standard ComboBox control.

I've tried to implement this myself using the DroppedDown property to make the list appear and use SelectedIndex to set the item but the content of the combobox's textbox is reset when I do that, while I only would like the "best matching item" to be highlighted from the ComboBox lists (I need "Suggest" and not "Append", Append-mode can not be really be used with substring-matching anyway).

I think that there must be a better way? If anyone knows of a custom / 3rd Party control doing this, I'm not against buying one either.

Thanks.

PS: I am programming in C# for WinForms, with .Net Framework 3.5.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

Here is the C# version. It has a lot of options to it.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            this.Load += new EventHandler(this.Form1_Load);

            InitializeComponent();
        }

    private clsCustomAutoCompleteTextbox ClsCustomAutoCompleteTextbox1 = null;

    private List<string> MasterList = new List<string> ();

    public void Form1_Load(object sender, System.EventArgs e) {
        this.ClsCustomAutoCompleteTextbox1 = new clsCustomAutoCompleteTextbox();

        this.ClsCustomAutoCompleteTextbox1.AutoCompleteFormBorder = System.Windows.Forms.FormBorderStyle.None;

        this.ClsCustomAutoCompleteTextbox1.AutoCompleteList = null;
        this.ClsCustomAutoCompleteTextbox1.Location = new System.Drawing.Point(27, 57);
        this.ClsCustomAutoCompleteTextbox1.Name = "clsCustomAutoCompleteTextbox1";
        this.ClsCustomAutoCompleteTextbox1.OnEnterSelect = true;
        this.ClsCustomAutoCompleteTextbox1.SelectionMethods = clsCustomAutoCompleteTextbox.SelectOptions.OnEnterSingleClick;
        this.ClsCustomAutoCompleteTextbox1.SelectTextAfterItemSelect = true;
        this.ClsCustomAutoCompleteTextbox1.ShowAutoCompleteOnFocus = false;
        this.ClsCustomAutoCompleteTextbox1.Size = new System.Drawing.Size(232, 20);
        this.ClsCustomAutoCompleteTextbox1.TabIndex = 0;

        this.Controls.Add(this.ClsCustomAutoCompleteTextbox1);

        this.ClsCustomAutoCompleteTextbox1.BeforeDisplayingAutoComplete +=
            new EventHandler<clsCustomAutoCompleteTextbox.clsAutoCompleteEventArgs>(BeforeDisplayingAutoComplete);

        List<string> L;
        L = new List<string>();
        L.Add("123123 - Bob");
        L.Add("534543 - Sally");
        L.Add("123123 - George");
        L.Add("34213 - Happy");
        MasterList = L;
        this.ClsCustomAutoCompleteTextbox1.AutoCompleteList = L;
    }

    private void BeforeDisplayingAutoComplete(object sender, clsCustomAutoCompleteTextbox.clsAutoCompleteEventArgs e) {
        string Name = this.ClsCustomAutoCompleteTextbox1.Text.ToLower();
        List<string> Display = new List<string> ();
        foreach (string Str in MasterList) {
            if ((Str.ToLower().IndexOf(Name) > -1)) {
                Display.Add(Str);
            }
        }
        e.AutoCompleteList = Display;
        e.SelectedIndex = 0;
    }
}
public class clsCustomAutoCompleteTextbox : TextBox
{
    private bool First = true;

    private object sender;

    private clsAutoCompleteEventArgs e;

    public List<string> test = new List<string> ();

    public int Tabs = 0;

    private int mSelStart;

    private int mSelLength;

    private List<string> myAutoCompleteList = new List<string> ();

    private ListBox myLbox = new ListBox();

    private Form myForm = new Form();

    private Form myParentForm;

    private bool DontHide = false;

    private bool SuspendFocus = false;

    private clsAutoCompleteEventArgs Args;

    private Timer HideTimer = new Timer();

    private Timer FocusTimer = new Timer();

    private bool myShowAutoCompleteOnFocus;

    private System.Windows.Forms.FormBorderStyle myAutoCompleteFormBorder = FormBorderStyle.None;

    private bool myOnEnterSelect;

    private int LastItem;

    private SelectOptions mySelectionMethods = (SelectOptions.OnDoubleClick | SelectOptions.OnEnterPress);

    private bool mySelectTextAfterItemSelect = true;

    private List<string> value;

    private int Cnt = 0;

    public bool SelectTextAfterItemSelect
    {
        get
        {
            return mySelectTextAfterItemSelect;
        }
        set
        {
            mySelectTextAfterItemSelect = value;
        }
    }

    [System.ComponentModel.Browsable(false)]
    public SelectOptions SelectionMethods
    {
        get
        {
            return mySelectionMethods;
        }
        set
        {
            mySelectionMethods = value;
        }
    }

    public bool OnEnterSelect
    {
        get
        {
            return myOnEnterSelect;
        }
        set
        {
            myOnEnterSelect = value;
        }
    }

    public System.Windows.Forms.FormBorderStyle AutoCompleteFormBorder
    {
        get
        {
            return myAutoCompleteFormBorder;
        }
        set
        {
            myAutoCompleteFormBorder = value;
        }
    }

    public bool ShowAutoCompleteOnFocus
    {
        get
        {
            return myShowAutoCompleteOnFocus;
        }
        set
        {
            myShowAutoCompleteOnFocus = value;
        }
    }

    public ListBox Lbox
    {
        get
        {
            return myLbox;
        }
    }

    public List<string> AutoCompleteList { get; set; }

    public event EventHandler<clsAutoCompleteEventArgs> BeforeDisplayingAutoComplete;

    public event EventHandler<clsItemSelectedEventArgs> ItemSelected;

    public enum SelectOptions
    {
        None = 0,

        OnEnterPress = 1,

        OnSingleClick = 2,

        OnDoubleClick = 4,

        OnTabPress = 8,

        OnRightArrow = 16,

        OnEnterSingleClick = 3,

        OnEnterSingleDoubleClicks = 7,

        OnEnterDoubleClick = 5,

        OnEnterTab = 9,
    }

    public class clsAutoCompleteEventArgs : EventArgs
    {

        private List<string> myAutoCompleteList;

        private bool myCancel;

        private int mySelectedIndex;

        private List<string> value;

        public int SelectedIndex
        {
            get
            {
                return mySelectedIndex;
            }
            set
            {
                mySelectedIndex = value;
            }
        }

        public bool Cancel
        {
            get
            {
                return myCancel;
            }
            set
            {
                myCancel = value;
            }
        }
        public List<string> AutoCompleteList { get; set; }
    }

    public override string SelectedText
    {
        get
        {
            return base.SelectedText;
        }
        set
        {
            base.SelectedText = value;
        }
    }

    public override int SelectionLength
    {
        get
        {
            return base.SelectionLength;
        }
        set
        {
            base.SelectionLength = value;
        }
    }

    public clsCustomAutoCompleteTextbox()
    {
        HideTimer.Tick += new EventHandler(HideTimer_Tick);
        FocusTimer.Tick += new EventHandler(FocusTimer_Tick);

        myLbox.Click += new EventHandler(myLbox_Click);
        myLbox.DoubleClick += new EventHandler(myLbox_DoubleClick);
        myLbox.GotFocus += new EventHandler(myLbox_GotFocus);
        myLbox.KeyDown += new KeyEventHandler(myLbox_KeyDown);

        myLbox.KeyUp += new KeyEventHandler(myLbox_KeyUp);
        myLbox.LostFocus += new EventHandler(myLbox_LostFocus);
        myLbox.MouseClick += new MouseEventHandler(myLbox_MouseClick);
        myLbox.MouseDoubleClick += new MouseEventHandler(myLbox_MouseDoubleClick);
        myLbox.MouseDown += new MouseEventHandler(myLbox_MouseDown);


        this.GotFocus += new EventHandler(clsCustomAutoCompleteTextbox_GotFocus);
        this.KeyDown += new KeyEventHandler(clsCustomAutoCompleteTextbox_KeyDown);
        this.Leave += new EventHandler(clsCustomAutoCompleteTextbox_Leave);
        this.LostFocus += new EventHandler(clsCustomAutoCompleteTextbox_LostFocus);
        this.Move += new EventHandler(clsCustomAutoCompleteTextbox_Move);
        this.ParentChanged += new EventHandler(clsCustomAutoCompleteTextbox_ParentChanged);


    }

    override protected void OnKeyUp(System.Windows.Forms.KeyEventArgs e)
    {


        base.OnKeyUp(e);
        ShowOnChar(new string(((char)(e.KeyValue)),1));
    }

    private void ShowOnChar(string C)
    {


        if (IsPrintChar(C))
        {
            this.ShowAutoComplete();
        }
    }

    private bool IsPrintChar(int C)
    {


        return IsPrintChar(((char)(C)));
    }

    private bool IsPrintChar(byte C)
    {


        return IsPrintChar(((char)(C)));
    }

    private bool IsPrintChar(char C)
    {


        return IsPrintChar(C.ToString());
    }

    private bool IsPrintChar(string C)
    {

        if (System.Text.RegularExpressions.Regex.IsMatch(C, "[^\t\n\r\f\v]"))
        {
            return true;
        }
        else
        {
            return false;
        }

    }

    private void clsCustomAutoCompleteTextbox_GotFocus(object sender, System.EventArgs e)
    {

        if ((!this.SuspendFocus
                    && (this.myShowAutoCompleteOnFocus
                    && (this.myForm.Visible == false))))
        {
            this.ShowAutoComplete();
        }

    }

    private void clsCustomAutoCompleteTextbox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    {

        if (!SelectItem(e.KeyCode, false, false))
        {
            if ((e.KeyCode == Keys.Up))
            {
                if ((myLbox.SelectedIndex > 0))
                {
                    MoveLBox((myLbox.SelectedIndex - 1));
                }
            }
            else if ((e.KeyCode == Keys.Down))
            {
                MoveLBox((myLbox.SelectedIndex + 1));
            }
        }

    }

    new void SelectAll()
    {
    }

    private void MoveLBox(int Index)
    {

        try
        {
            if ((Index
                        > (myLbox.Items.Count - 1)))
            {
                Index = (myLbox.Items.Count - 1);
            }
            myLbox.SelectedIndex = Index;
        }
        catch
        {
        }

    }

    private void clsCustomAutoCompleteTextbox_Leave(object sender, System.EventArgs e)
    {

        DoHide(sender, e);

    }

    private void clsCustomAutoCompleteTextbox_LostFocus(object sender, System.EventArgs e)
    {

        DoHide(sender, e);

    }

    private void clsCustomAutoCompleteTextbox_Move(object sender, System.EventArgs e)
    {

        MoveDrop();

    }

    private void clsCustomAutoCompleteTextbox_ParentChanged(object sender, System.EventArgs e)
    {

        if (myParentForm != null) myParentForm.Deactivate -= new EventHandler(myParentForm_Deactivate);
        myParentForm = GetParentForm(this);
        if (myParentForm != null) myParentForm.Deactivate += new EventHandler(myParentForm_Deactivate);
    }

    private void HideTimer_Tick(object sender, System.EventArgs e)
    {

        MoveDrop();
        DoHide(sender, e);
        Cnt++;
        if ((Cnt > 300))
        {
            if (!AppHasFocus(""))
            {
                DoHideAuto();
            }
            Cnt = 0;
        }

    }

    private void myLbox_Click(object sender, System.EventArgs e)
    {
    }

    private void myLbox_DoubleClick(object sender, System.EventArgs e)
    {
    }

    private bool SelectItem(Keys Key, bool SingleClick)
    {
        return SelectItem(Key, SingleClick, false);
    }

    private bool SelectItem(Keys Key)
    {
        return SelectItem(Key, false, false);
    }

    private bool SelectItem(Keys Key, bool SingleClick, bool DoubleClick)
    {

        // Warning!!! Optional parameters

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

...