C#实现自动完成功能(人生第一次造轮子)

这个主要实现的是一个自动完成的功能,C#本身提供的自动完成效果并不好,所以自己造了一个轮子。。。。

实现这个功能依靠于两个控件一个是ListBox,一个是ComboBox。ComboBox是在类外定义的,就是进行模糊查询时输入值的控件,该控件的Dropdownstyle要设置为Simple。实现的主要原理是输入值后触发相应事件,生成一个ListBox控件,并进行查询,将查询结果填入ListBox控件,通过计算ComboBox控件的位置,将ListBox控件挂到ComboBox的下方。通过函数重载在查询时提供两种方法,一种是支持Sqlsever相关查询语句的内部查询方法,该方法在类内实现,需要提供相关的Sql查询方法,这里使用的是Sql的存储过程,可能要略作修改。还有一种是外部查询,在类外写相关的查询方法,并通过委托传入类内。另外提供了两个外部方法,用于选定查询结果触发后续事件,依然是通过委托传入类内。

代码如下:

<p align="left"><span style="color:blue;">using</span> System;</p><p align="left"><span style="color:blue;">using</span> System.Collections.Generic;</p><p align="left"><span style="color:blue;">using</span> System.Data;</p><p align="left"><span style="color:blue;">using</span> System.Drawing;</p><p align="left"><span style="color:blue;">using</span> System.Linq;</p><p align="left"><span style="color:blue;">using</span> System.Runtime.InteropServices;</p><p align="left"><span style="color:blue;">using</span> System.Text;</p><p align="left"><span style="color:blue;">using</span> System.Threading.Tasks;</p><p align="left"><span style="color:blue;">using</span> System.Windows.Forms;</p><p align="left"><span style="color:blue;">using</span> TNB.pubClass;</p>

/*
C#实现自动完成功能
2016年10月14日
*/

namespace TNB
{
    class AutoComplete
    {
        public delegate List<string> External_Query();        //外部查询方法委托(返回值为List<string>,无参数)
        External_Query ExternalQuery;       //外部查询方法
        public delegate void External_del();        //外部事件处理方法委托(返回值为空,无参数)
        External_del REvent_Strike;     //外部事件处理方法(触发)
        External_del REvent_Reset;     //外部事件处理方法(恢复)
        ComboBox rec_Com;       //ComboBox控件
        ListBox rec_List;               //ListBox控件
        string search_value="";      //输入查询值
        bool ExtQueryFlag = false;      //是否使用外部查询标志
        //数据库相关参数字段
        string Table;       //数据库表名
        string Columns;     //数据库列
        string PYixcol;         //数据库拼音缩写列
        string Nameixcol;       //数据库名称列
        string Col1;    //数据库序号列
        int Retindex;       //数据库查询结果列列号(0开始)
        int MaxItems;          //最大显示条数

        public AutoComplete() { }


        //绑定控件、外部事件处理方法
        //参数说明 1.Com:查询是输入值得ComboBox控件 2.Gb(P) 控件所在父容器 3. Fun_Strike :选定查询结果的后续触发事件方法 
        //4.Fun_Rest :删除查询结果触发事件的恢复方法  5.X:ComboBox控件X坐标 6.Y:ComboBox控件Y坐标
        //不提供ComboBox在屏幕中的位置坐标,并且父窗体为GroupBox
        public void Binding_Extern(ComboBox Com, GroupBox Gb, External_del Fun_Strike=null, External_del Fun_Reset=null)
        {
            //绑定方法
            if (Fun_Strike != null)
                REvent_Strike = Fun_Strike;        //绑定外部事件处理方法(触发)
            else
                REvent_Strike = EmptyFun;       //绑定空方法
            if(Fun_Reset!=null)
                REvent_Reset = Fun_Reset;       //绑定外部事件处理方法(恢复)
            else
                REvent_Reset = EmptyFun;       //绑定空方法
            rec_Com = Com;      //绑定外部ComboBox控件

            //动态创建ListBox控件
            rec_List = new ListBox();   //实例化控件
            int LocationX = Com.Location.X;     //控件位置X
            int LocationY = Com.Location.Y + 19;        //控件位置Y
            int Width = Com.Size.Width;     //控件大小
            rec_List.Location = new Point(LocationX, LocationY);     //设置控件位置
            rec_List.Size = new Size(Width, 0);      //设置控件大小
            rec_List.Visible = false;       //控件初始化为隐藏
            Gb.Controls.Add(rec_List);      //添加到所在GroupBox
            rec_List.BringToFront();        //设置控件最上层显示

            //注册控件事件
            rec_List.Click += new System.EventHandler(ListBox_Click);     //ListBox的单击事件
            rec_List.SelectedIndexChanged += new System.EventHandler(ListBox_SelectedIndexChanged);     //ListBox的选中值改变事件
            rec_Com.Click += new System.EventHandler(ComboBox_Click);      //ComboBox的单击事件
            rec_Com.KeyDown += new System.Windows.Forms.KeyEventHandler(ComboBox_KeyDown);      //ComboBox的按键事件
            rec_Com.TextUpdate += new System.EventHandler(ComboBox_TextUpdate);        //ComboBox的文本更新事件
            rec_Com.TextChanged += new System.EventHandler(ComboBox_TextChanged);        //ComboBox的文本改变事件
        }
        //提供ComboBox在屏幕中的位置坐标,并且父窗体为GroupBox
        public void Binding_Extern(ComboBox Com, GroupBox Gb, int X,int Y,External_del Fun_Strike = null, External_del Fun_Reset = null)
        {
            //绑定方法
            if (Fun_Strike != null)
                REvent_Strike = Fun_Strike;        //绑定外部事件处理方法(触发)
            else
                REvent_Strike = EmptyFun;       //绑定空方法
            if (Fun_Reset != null)
                REvent_Reset = Fun_Reset;       //绑定外部事件处理方法(恢复)
            else
                REvent_Reset = EmptyFun;       //绑定空方法
            rec_Com = Com;      //绑定外部ComboBox控件

            //动态创建ListBox控件
            rec_List = new ListBox();   //实例化控件
            int LocationX = X;     //控件位置X
            int LocationY = Y;        //控件位置Y
            int Width = Com.Size.Width;     //控件大小
            rec_List.Location = new Point(LocationX, LocationY);     //设置控件位置
            rec_List.Size = new Size(Width, 0);      //设置控件大小
            rec_List.Visible = false;       //控件初始化为隐藏
            Gb.Controls.Add(rec_List);      //添加到所在GroupBox
            rec_List.BringToFront();        //设置控件最上层显示

            //注册控件事件
            rec_List.Click += new System.EventHandler(ListBox_Click);     //ListBox的单击事件
            rec_List.SelectedIndexChanged += new System.EventHandler(ListBox_SelectedIndexChanged);     //ListBox的选中值改变事件
            rec_Com.Click += new System.EventHandler(ComboBox_Click);      //ComboBox的单击事件
            rec_Com.KeyDown += new System.Windows.Forms.KeyEventHandler(ComboBox_KeyDown);      //ComboBox的按键事件
            rec_Com.TextUpdate += new System.EventHandler(ComboBox_TextUpdate);        //ComboBox的文本更新事件
            rec_Com.TextChanged += new System.EventHandler(ComboBox_TextChanged);        //ComboBox的文本改变事件
        }
        //不提供ComboBox在屏幕中的位置坐标,并且父窗体为Panel
        public void Binding_Extern(ComboBox Com, Panel P, External_del Fun_Strike = null, External_del Fun_Reset = null)
        {
            //绑定方法
            if (Fun_Strike != null)
                REvent_Strike = Fun_Strike;        //绑定外部事件处理方法(触发)
            else
                REvent_Strike = EmptyFun;       //绑定空方法
            if (Fun_Reset != null)
                REvent_Reset = Fun_Reset;       //绑定外部事件处理方法(恢复)
            else
                REvent_Reset = EmptyFun;       //绑定空方法
            rec_Com = Com;      //绑定外部ComboBox控件

            //动态创建ListBox控件
            rec_List = new ListBox();   //实例化控件
            int LocationX = Com.Location.X;     //控件位置X
            int LocationY = Com.Location.Y + 19;        //控件位置Y
            int Width = Com.Size.Width;     //控件大小
            rec_List.Location = new Point(LocationX, LocationY);     //设置控件位置
            rec_List.Size = new Size(Width, 0);      //设置控件大小
            rec_List.Visible = false;       //控件初始化为隐藏
            P.Controls.Add(rec_List);      //添加到所在GroupBox
            rec_List.BringToFront();        //设置控件最上层显示

            //注册控件事件
            rec_List.Click += new System.EventHandler(ListBox_Click);     //ListBox的单击事件
            rec_List.SelectedIndexChanged += new System.EventHandler(ListBox_SelectedIndexChanged);     //ListBox的选中值改变事件
            rec_Com.Click += new System.EventHandler(ComboBox_Click);      //ComboBox的单击事件
            rec_Com.KeyDown += new System.Windows.Forms.KeyEventHandler(ComboBox_KeyDown);      //ComboBox的按键事件
            rec_Com.TextUpdate += new System.EventHandler(ComboBox_TextUpdate);        //ComboBox的文本更新事件
            rec_Com.TextChanged += new System.EventHandler(ComboBox_TextChanged);        //ComboBox的文本改变事件
        }
        //提供ComboBox在屏幕中的位置坐标,并且父窗体为Panel
        public void Binding_Extern(ComboBox Com, Panel P, int X, int Y, External_del Fun_Strike = null, External_del Fun_Reset = null)
        {
            //绑定方法
            if (Fun_Strike != null)
                REvent_Strike = Fun_Strike;        //绑定外部事件处理方法(触发)
            else
                REvent_Strike = EmptyFun;       //绑定空方法
            if (Fun_Reset != null)
                REvent_Reset = Fun_Reset;       //绑定外部事件处理方法(恢复)
            else
                REvent_Reset = EmptyFun;       //绑定空方法
            rec_Com = Com;      //绑定外部ComboBox控件

            //动态创建ListBox控件
            rec_List = new ListBox();   //实例化控件
            int LocationX = X;     //控件位置X
            int LocationY = Y;        //控件位置Y
            int Width = Com.Size.Width;     //控件大小
            rec_List.Location = new Point(LocationX, LocationY);     //设置控件位置
            rec_List.Size = new Size(Width, 0);      //设置控件大小
            rec_List.Visible = false;       //控件初始化为隐藏
            P.Controls.Add(rec_List);      //添加到所在GroupBox
            rec_List.BringToFront();        //设置控件最上层显示

            //注册控件事件
            rec_List.Click += new System.EventHandler(ListBox_Click);     //ListBox的单击事件
            rec_List.SelectedIndexChanged += new System.EventHandler(ListBox_SelectedIndexChanged);     //ListBox的选中值改变事件
            rec_Com.Click += new System.EventHandler(ComboBox_Click);      //ComboBox的单击事件
            rec_Com.KeyDown += new System.Windows.Forms.KeyEventHandler(ComboBox_KeyDown);      //ComboBox的按键事件
            rec_Com.TextUpdate += new System.EventHandler(ComboBox_TextUpdate);        //ComboBox的文本更新事件
            rec_Com.TextChanged += new System.EventHandler(ComboBox_TextChanged);        //ComboBox的文本改变事件
        }


        //绑定查询
        //绑定内部查询,使用SqlSever数据库查询
        //参数说明:1.table:表名   2.columns:表中所有列   3.pyixcol:拼音首字母索引列   4.nameixcol:中文名称索引列   5.col1:排序列   
        //6.Retindex:查询内容列索引(0开始)  7.maxItems: ListBox控件显示的最大条目
        public void Binding_DataBase(string table, string columns, string pyixcol, string nameixcol, string col1, int retindex,int maxItems)       
        {
            Table = table;
            Columns = columns;
            PYixcol = pyixcol;
            Nameixcol = nameixcol;
            Col1 = col1;
            Retindex = retindex;
            MaxItems = maxItems;
        }
        
        //绑定外部查询,提供外部查询方法
        //参数说明 1.ExtQuery:外部查询方法函数委托 2.maxItems: ListBox控件显示的最大条目
        public void Binding_DataBase(External_Query ExtQuery,int maxItems)
        {
            ExternalQuery = ExtQuery;
            MaxItems = maxItems;
            ExtQueryFlag = true;
        }


        //内部查询方法
        private void Query1()
        {
            //符合查询条件
            if (rec_Com.Text.Trim() != "" && rec_Com.Text.Trim() != "%")
            {
                //模糊查询部分
                HashSet<string> Hset = new HashSet<string>();       //初始化查询hash结果集合
                string STR = "";       //查询内容初始化
                string logo = "";       //查询串初始化
                bool flag = false;          //查询标志初始化 (查询成功为true)
                //1.字符串匹配查询
                STR = rec_Com.Text.Trim();      //获取查询内容
                #region 字符串匹配查询
                logo = Nameixcol + " LIKE" + "'" + STR + "%" + "'";
                DataSet J1 = new DataSet();
                try
                {
                    int c1 = 0;
                    DataBaseAccess.GetPageRecord(1000, 1, Columns, Table, logo, Col1, false, "", ref c1, ref J1);
                }
                catch (Exception Error)
                {
                    MessageBox.Show(Error.Message.ToString());
                }
                //字符串匹配查询结果装填到hash结果集
                if (J1.Tables[0].Rows.Count > 0)
                {
                    for (int k = 0; k < J1.Tables[0].Rows.Count; ++k)
                        Hset.Add(J1.Tables[0].Rows[k][Retindex].ToString());
                    flag = true;    //改变查询结果标志
                }
                #endregion
                //2.字符串拼音首字母查询
                STR = ConvertToFirstSpell(STR);        //将查询内容转换为拼音首字母组成的字符串
                #region 拼音首字母查询
                logo = PYixcol + " LIKE" + "'" + STR + "%" + "'";
                DataSet J2 = new DataSet();
                try
                {
                    int c1 = 0;
                    DataBaseAccess.GetPageRecord(1000, 1, Columns, Table, logo, Col1, false, "", ref c1, ref J2);
                }
                catch (Exception Error)
                {
                    MessageBox.Show(Error.Message.ToString());
                }
                //字符串拼音首字母查询结果装填到hash结果集
                if (J2.Tables[0].Rows.Count > 0)
                {
                    for (int k = 0; k < J2.Tables[0].Rows.Count; ++k)       //装填items
                        Hset.Add(J2.Tables[0].Rows[k][Retindex].ToString());
                    flag = true;
                }
                #endregion
                //hash结果集处理部分
                #region hash结果集非空
                if (flag)
                {
                    int cnt = Hset.Count;       //获取hash结果集条数
                    //设置Listbox控件的大小
                    int ListBoxSize = Convert.ToInt32(rec_List.Font.Size * 1.5);
                    if (cnt > MaxItems)
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, 15 * MaxItems);
                    else if (cnt == 1)
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, ListBoxSize + 5);
                    else
                    {
                        int weight = ListBoxSize * cnt;       //计算listbox高度
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, weight);
                    }
                    //装填集合
                    rec_List.Items.Clear();      //清空Listbox原来内容
                    rec_List.Items.AddRange(Hset.ToArray());      //将hash结果集装入Listbox
                    rec_List.Visible = true;     //显示下拉  
                    search_value = rec_Com.Text;        //获取初始查询之
                }
                #endregion
                #region hash结果集为空
                else
                {
                    rec_List.Visible = false;        //关闭下拉
                    rec_List.Items.Clear();      //清空条目
                }
                #endregion
            }
            //不符合查询条件
            else
            {
                rec_List.Visible = false;        //关闭下拉
                rec_List.Items.Clear();     //清空
            }
            rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾
        }
        //外部查询方法
        private void Query2()
        {
            //符合查询要求
            if (rec_Com.Text.Trim() != "")
            {
                List<string> list = ExternalQuery();
                if (list.Count != 0)
                {
                    #region 传入结果集非空处理方法
                    int cnt = list.Count;       //获取结果集条数
                    //设置Listbox控件的大小
                    int ListBoxSize = Convert.ToInt32(rec_List.Font.Size * 1.5);
                    if (cnt > MaxItems)
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, 15 * MaxItems);
                    else if (cnt == 1)
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, ListBoxSize + 5);
                    else
                    {
                        int weight = ListBoxSize * cnt;       //计算listbox高度
                        rec_List.SetBounds(rec_List.Location.X, rec_List.Location.Y, rec_List.Width, weight);
                    }
                    //装填集合
                    rec_List.Items.Clear();      //清空Listbox原来内容
                    rec_List.Items.AddRange(list.ToArray());      //将hash结果集装入Listbox
                    rec_List.Visible = true;     //显示下拉  
                    search_value = rec_Com.Text;        //获取初始查询之
                    #endregion
                }
                else   //结果集为空处理方法
                {
                    rec_List.Visible = false;        //关闭下拉
                    rec_List.Items.Clear();      //清空条目
                }
            }
            else   //不符合查询要求
            {
                rec_List.Visible = false;        //关闭下拉
                rec_List.Items.Clear();      //清空条目
            }
            rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾
        }


        //事件定义
        //ListBox的单击事件(实现鼠标单击选择)
        private void ListBox_Click(object sender, EventArgs e)
        {
            string Selvalue;        //选中值
            if ((Selvalue = rec_List.SelectedItem.ToString()) != "")        //存在选中内容
            {
                rec_Com.Text = Selvalue;        //将选中值在ComboBox中显示
                rec_Com.Focus();        //设置焦点到ComboBox
                rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾 
                search_value = rec_Com.Text;        //更新输入查询
                rec_List.Visible = false;       //关闭下拉
            }
        }
    
        //ListBox的选中改变事件 (实现ComboBox中文本的改变)
        private void ListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (rec_List.SelectedIndex == -1)
            {
                rec_Com.Text = search_value;        //更新输入查询值
                rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾 
            }
            else
            {
                rec_Com.Text = rec_List.SelectedItem.ToString();        //改变ComboBox内容
                rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾 
            }
        }

        //ComboBox的单击事件 (实现单击显示下拉窗体)
        private void ComboBox_Click(object sender, EventArgs e)
        {
            if (rec_Com.Text != "" && rec_List.Items.Count != 0)        //如果存在查询内容,并且有查询结果
                rec_List.Visible = true;        //打开下拉
        }

        //ComboBox的按键事件 (实现键盘上下键移动选中选项和回车确认选中项)
        private void ComboBox_KeyDown(object sender, KeyEventArgs e)
        {
            //下一项操作
            if (e.KeyCode == Keys.Down && rec_List.Visible == true)
            {
                rec_List.SelectedIndex++;       //向下移动选中项 
            }
            //上一项操作
            else if (e.KeyCode == Keys.Up && rec_List.Visible == true)
            {
                rec_List.SelectedIndex--;       //向上移动选中项
            }
            //确认选中项
            else if (e.KeyCode == Keys.Enter)
            {
                    rec_List.Visible = false;       //关闭下拉
                    search_value = rec_Com.Text;        //更新输入值
                    rec_Com.SelectionStart = rec_Com.Text.Length;     //设置光标位置到文字结尾 
            }
        }

        //ComboBox的文本更新事件 (实现输入文本后进行的模糊查询)
        private void ComboBox_TextUpdate(object sender, EventArgs e)
        {
            if (ExtQueryFlag)
            {
                Query2();
            }
            else
            {
                Query1();
            }
        }

        //ComboBox的文本改变事件 (实现文本改变后的调用外部事件处理方法)
        private void ComboBox_TextChanged(object sender, EventArgs e)
        {
            //如果没有查询项(那么一定不符合要求)
            if (rec_List.Items.Count == 0)   
            {
                REvent_Reset();      //调用外部关联事件处理方法(恢复)
            }
            //存在查询项(判断确认的文本是否符合要求)
            else   
            {
                bool flag = false;      //是否符合要求的标志
                for (int i = 0; i < rec_List.Items.Count; ++i)
                {
                    if (rec_Com.Text == rec_List.Items[i].ToString())       //符合要求
                    {
                        flag = true;
                        break;
                    }
                }
                if(flag)
                    REvent_Strike();    //调用外部关联事件处理方法(触发)
                else 
                    REvent_Reset();  //调用外部关联事件处理方法(恢复)
            }
        }


        //汉字拼音转换(用于模糊查询)
        public string ConvertToFirstSpell(string strChinese)
        {
            int len = strChinese.Length;
            string myStr = "";
            for (int i = 0; i < len; i++)
            {
                myStr += GetFirstSpell(strChinese.Substring(i, 1));
            }
            return myStr;
        }
        //获取第一个汉字的首字母(大写)(用于模糊查询)
        public string GetFirstSpell(string charChinese)
        {
            byte[] arrCN = Encoding.Default.GetBytes(charChinese);
            if (arrCN.Length > 1)
            {
                int area = (short)arrCN[0];
                int pos = (short)arrCN[1];
                int code = (area << 8) + pos;
                int[] areacode = { 45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 48119, 48119, 49062, 49324, 49896, 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52698, 52698, 52698, 52980, 53689, 54481 };
                for (int i = 0; i < 26; i++)
                {
                    int max = 55290;
                    if (i != 25) max = areacode[i + 1];
                    if (areacode[i] <= code && code < max)
                    {
                        byte[] bytes = new byte[] { (byte)(65 + i) };
                        return Encoding.Default.GetString(bytes, 0, bytes.Length);
                    }
                }
                return "*";
            }
            else return charChinese;
        }

        //空方法
        private void EmptyFun()
        {

        }

        ~AutoComplete()
        {
            rec_List.Dispose();     //销毁List控件
        }
    }
}
</span>


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值