zoukankan      html  css  js  c++  java
  • WinForm 自动完成控件

    在Web的应用方面有js的插件实现自动完成(或叫智能提示)功能,但在WinForm窗体应用方面就没那么好了。

    TextBox控件本身是提供了一个自动提示功能,只要用上这三个属性:

    AutoCompleteCustomSource:AutoCompleteSource 属性设置为CustomSource 时要使用的 StringCollection。

    AutoCompleteMode: 指示文本框的文本完成行为。

    AutoCompleteSource:自动完成源,可以是 AutoCompleteSource 的枚举值之一。

    就行了, 一个简单的示例如下

    textBox1.AutoCompleteCustomSource .AddRange(new string[] { "java","javascript","js","c#","c","c++" });
    textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
    textBox1.AutoCompleteSource
    = AutoCompleteSource.CustomSource;

     可是这种方式的不支持我们中文的简拼自动完成(如在文本框里输入"gz"就会出现"广州")。只好自己写一个支持简拼自动完成的控件了。

    这是效果图

    控件不太复杂,一个TextBox和一个ListBox。代码方面,用DataTable作数据源,每次在TextBox的值时,通过DataTable的Select方法,配上合适的表达式(如:{0} like '{1}%' and IsNull([{2}], ' ') <> ' ')来筛选出合适的备选文本内容,以下则是控件的代码:

    变量
    1         private TextBox _tb;
    2         private ListBox _lb;
    3         private DataTable _dt_datasource;
    4         private bool _text_lock;
    5         private string _general_text;//原始输入文本框的值
    6         private bool _lb_kd_first_top;//listbox是否第一次到达顶部
    7         private int _itemCount;
    属性
     1         /// <summary>
     2         /// TextBox的Text属性,增加了_text_lock操作,放置触发TextChanged事件
     3         /// </summary>
     4         private string TextBoxText 
     5         {
     6             get { return _tb.Text; }
     7             set
     8             {
     9                 _text_lock = true;
    10                 _tb.Text = value;
    11                 _text_lock = false;
    12             }
    13         }
    14 
    15         /// <summary>
    16         /// 显示在ListBox的字段名
    17         /// </summary>
    18         public string ValueName { get; set; }
    19 
    20         /// <summary>
    21         /// 用于匹配的字段名
    22         /// </summary>
    23         public string CodeName { get; set; }
    24 
    25         /// <summary>
    26         /// 显示提示项的数量
    27         /// </summary>
    28         public int ItemCount
    29         {
    30             get
    31             { return _itemCount; }
    32             set
    33             {
    34                 if (value <= 0)
    35                     _itemCount = 1;
    36                 else
    37                     _itemCount = value;
    38             }
    39         }
    40 
    41         public DataTable DataSource
    42         {
    43             get { return _dt_datasource; }
    44             set { _dt_datasource = value; }
    45         }
    构造函数
    1         public AutoComplete()
    2         {
    3             InitialControls();
    4         }
    控件事件
     1         void AutoComplete_Load(object sender, EventArgs e)
     2         {
     3             _tb.Width = this.Width;
     4             _lb.Width = _tb.Width;
     5             this.Height = _tb.Height-1;
     6         }
     7 
     8         void AutoComplete_LostFocus(object sender, EventArgs e)
     9         {
    10             _lb.Visible = false;
    11             this.Height = _tb.Height-1;
    12         }
    列表框事件
     1         //列表框按键事件
     2         void _lb_KeyDown(object sender, KeyEventArgs e)
     3         {
     4             if (_lb.Items.Count == 0 || !_lb.Visible) return;
     5 
     6             if (!_lb_kd_first_top && ((e.KeyCode == Keys.Up && _lb.SelectedIndex == 0) || (e.KeyCode == Keys.Down && _lb.SelectedIndex == _lb.Items.Count)))
     7             {
     8                 _lb.SelectedIndex = -1;
     9                 TextBoxText = _general_text;
    10             }
    11             else
    12             {
    13                 TextBoxText = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    14                 _lb_kd_first_top = _lb.SelectedIndex != 0;
    15             }
    16 
    17             if (e.KeyCode == Keys.Enter && _lb.SelectedIndex != -1)
    18             {
    19                 _lb.Visible = false;
    20                 this.Height = _tb.Height;
    21                 _tb.Focus();
    22             }
    23         }
    24 
    25         //列表鼠标单击事件
    26         void _lb_Click(object sender, EventArgs e)
    27         {
    28             if (_lb.SelectedIndex != -1)
    29             {
    30                 TextBoxText = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    31             }
    32             _lb.Visible = false;
    33             _tb.Focus();
    34             this.Height = _tb.Height;
    35         }
    文本框事件
     1         //文本框按键事件
     2         void _tb_KeyDown(object sender, KeyEventArgs e)
     3         {
     4             if (_lb.Items.Count == 0||!_lb.Visible) return;
     5 
     6             bool _is_set = false;
     7 
     8             if (e.KeyCode == Keys.Up)
     9             {
    10                 if (_lb.SelectedIndex <= 0)
    11                 {
    12                     _lb.SelectedIndex = -1;
    13                     TextBoxText = _general_text;
    14                 }
    15                 else
    16                 {
    17                     _lb.SelectedIndex--;
    18                     _is_set = true;
    19                 }
    20             }
    21             else if (e.KeyCode == Keys.Down)
    22             {
    23                 if (_lb.SelectedIndex == _lb.Items.Count - 1)
    24                 {
    25                     _lb.SelectedIndex = 0; 
    26                     _lb.SelectedIndex = -1;
    27                     TextBoxText = _general_text;
    28                 }
    29                 else
    30                 {
    31                     _lb.SelectedIndex++;
    32                     _is_set = true;
    33                 }
    34             }
    35             else if (e.KeyCode == Keys.Enter)
    36             {
    37                 _lb.Visible = false;
    38                 this.Height = _tb.Height;
    39                 _is_set = _lb.SelectedIndex != -1;
    40             }
    41 
    42             _lb_kd_first_top = _lb.SelectedIndex != 0;
    43             if (_is_set)
    44             { 
    45                 _text_lock = true;
    46                 _tb.Text = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    47                 _tb.SelectionStart = _tb.Text.Length + 10;
    48                 _tb.SelectionLength = 0;
    49                 _text_lock = false;
    50             }
    51         }
    52 
    53         //文本框文本变更事件
    54         void _tb_TextChanged(object sender, EventArgs e)
    55         {
    56             if (_text_lock) return;
    57             _general_text = _tb.Text;
    58             _lb.Visible = true;
    59             _lb.Height = _lb.ItemHeight * (_itemCount+1);
    60             this.BringToFront();
    61             _lb.BringToFront();
    62             this.Height = _tb.Height + _lb.Height;
    63 
    64             DataTable temp_table = _dt_datasource.Clone();
    65             string filtStr = FormatStr(_tb.Text);
    66             DataRow [] rows = _dt_datasource.Select(string.Format(GetFilterStr(),CodeName,filtStr,_lb.DisplayMember));
    67             for (int i = 0; i < rows.Length&&i<_itemCount; i++)
    68             {
    69                 temp_table.Rows.Add(rows[i].ItemArray);
    70             }
    71             _lb.DataSource = temp_table;
    72             if (_lb.Items.Count > 0) _lb.SelectedItem = _lb.Items[0];
    73         }
    方法
     1         /// <summary>
     2         /// 初始化控件
     3         /// </summary>
     4         private void InitialControls()
     5         {
     6             _lb_kd_first_top = true;
     7 
     8             _tb = new TextBox();
     9             _tb.Location = new Point(0, 0);
    10             _tb.Margin = new System.Windows.Forms.Padding(0);
    11             _tb.Width = this.Width;
    12             _tb.TextChanged += new EventHandler(_tb_TextChanged);
    13             _tb.KeyUp += new KeyEventHandler(_tb_KeyDown);
    14 
    15             _lb = new ListBox();
    16             _lb.Visible = false;
    17             _lb.Width = _tb.Width;
    18             _lb.Margin = new System.Windows.Forms.Padding(0);
    19             _lb.DisplayMember = ValueName;
    20             _lb.SelectionMode = SelectionMode.One;
    21             _lb.Location = new Point(0, _tb.Height);
    22             _lb.KeyUp += new KeyEventHandler(_lb_KeyDown);
    23             _lb.Click += new EventHandler(_lb_Click);
    24 
    25             this.Controls.Add(_tb);
    26             this.Controls.Add(_lb);
    27             this.Height = _tb.Height - 1;
    28             this.LostFocus += new EventHandler(AutoComplete_LostFocus);
    29             this.Leave += new EventHandler(AutoComplete_LostFocus);
    30             this.Load += new EventHandler(AutoComplete_Load);
    31         }
    32 
    33         /// <summary>
    34         /// 获取过滤格式字符串
    35         /// </summary>
    36         /// <returns></returns>
    37         private string GetFilterStr()
    38         {
    39             //未过滤注入的字符 ' ] %任意  *任意
    40             string filter = " {0} like '{1}%' and IsNull([{2}], ' ') <> ' '  ";
    41             if (_dt_datasource.Rows[0][CodeName].ToString().LastIndexOf(';') > -1)
    42                 filter = " {0} like '%;{1}%' and IsNull([{2}],' ') <> ' ' ";
    43 
    44             return filter;
    45         }
    46 
    47         /// <summary>
    48         /// 过滤字符串中一些可能造成出错的字符
    49         /// </summary>
    50         /// <param name="str"></param>
    51         /// <returns></returns>
    52         private string FormatStr(string str)
    53         {
    54             if (string.IsNullOrEmpty(str)) return string.Empty;
    55             str = str.Replace("[", "[[]").Replace("%", "[%]").Replace("*", "[*]").Replace("'", "''");
    56             if (CodeName == "code") str = str.Replace(" ", "");
    57             return str;
    58         }

    下面是使用控件的例子

              class Common
        {
            /// <summary>
            /// 生成测试数据源
            /// </summary>
            public static DataTable CreateTestDataSoucre
            {
                get
                {
                    List<KeyValuePair<string, string>> source = new List<KeyValuePair<string, string>>() 
                    {
                        new KeyValuePair<string,string>("张三",";zs;张三;"),
                        new KeyValuePair<string,string>("李四",";li;李四;"),
                        new KeyValuePair<string,string>("王五",";ww;王五;"),
                        new KeyValuePair<string,string>("赵六",";zl;赵六;"),
                        new KeyValuePair<string,string>("洗刷",";cs;csharp;c#;洗刷;"),
                        new KeyValuePair<string,string>("爪哇",";java;爪哇;"),
                        new KeyValuePair<string,string>("java",";java;"),
                        new KeyValuePair<string,string>("c#",";c#;cs;csharp;"),
                        new KeyValuePair<string,string>("javascript",";javascript;js;")
                    };
    
                    DataTable table = new DataTable();
    
                    table.Columns.Add("id");
                    table.Columns.Add("name");
                    table.Columns.Add("code");
    
                    for (int i = 0; i < source.Count; i++)
                    {
                        DataRow row = table.Rows.Add();
                        row["id"] = i;
                        row["name"] = source[i].Key;
                        row["code"] = source[i].Value;
                    }
    
                    return table;
                }
            }
        } 
    
                 //.............
                 AutoComplete ac=new AutoComplete();
                ac.ValueName = "name";
                ac.CodeName = "code";
                ac.DataSource= Common.CreateTestDataSoucre;
                ac.ItemCount= 5;                        
  • 相关阅读:
    【LeetCode-树】找树左下角的值
    【LeetCode-贪心】合并区间
    MongoDB3.6版本新增特性
    MongoDB initial sync过程
    MongoDB3.4版本新增特性
    保险配置原则
    MongoDB批量操作时字段为null时没有入库
    Kafka消费者没有收到通知的分析
    Git分支的管理
    NoSQLBooster如何MongoDB的部分文档从一个集合拷贝到另外一个集合中
  • 原文地址:https://www.cnblogs.com/HopeGi/p/2830813.html
Copyright © 2011-2022 走看看