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"就会出现"广州")。只好自己写一个支持简拼自动完成的控件了。

这是效果图WinForm 自动完成控件

控件不太复杂,一个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;                        

 

 

你可能感兴趣的:(WinForm)