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}], ' ') <> ' ')来筛选出合适的备选文本内容,以下则是控件的代码:
    复制代码 代码如下:
    private TextBox _tb;
    private ListBox _lb;
    private DataTable _dt_datasource;
    private bool _text_lock;
    private string _general_text;//原始输入文本框的值
    private bool _lb_kd_first_top;//listbox是否第一次到达顶部
    private int _itemCount;

    复制代码 代码如下:
    /// <summary>
    /// TextBox的Text属性,增加了_text_lock操作,放置触发TextChanged事件
    /// </summary>
    private string TextBoxText
    {
    get { return _tb.Text; }
    set
    {
    _text_lock = true;
    _tb.Text = value;
    _text_lock = false;
    }
    }
    /// <summary>
    /// 显示在ListBox的字段名
    /// </summary>
    public string ValueName { get; set; }
    /// <summary>
    /// 用于匹配的字段名
    /// </summary>
    public string CodeName { get; set; }
    /// <summary>
    /// 显示提示项的数量
    /// </summary>
    public int ItemCount
    {
    get
    { return _itemCount; }
    set
    {
    if (value <= 0)
    _itemCount = 1;
    else
    _itemCount = value;
    }
    }
    public DataTable DataSource
    {
    get { return _dt_datasource; }
    set { _dt_datasource = value; }
    }

    复制代码 代码如下:
    public AutoComplete()
    {
    InitialControls();
    }

    复制代码 代码如下:
    void AutoComplete_Load(object sender, EventArgs e)
    {
    _tb.Width = this.Width;
    _lb.Width = _tb.Width;
    this.Height = _tb.Height-1;
    }
    void AutoComplete_LostFocus(object sender, EventArgs e)
    {
    _lb.Visible = false;
    this.Height = _tb.Height-1;
    }

    复制代码 代码如下:
    //列表框按键事件
    void _lb_KeyDown(object sender, KeyEventArgs e)
    {
    if (_lb.Items.Count == 0 || !_lb.Visible) return;
    if (!_lb_kd_first_top && ((e.KeyCode == Keys.Up && _lb.SelectedIndex == 0) || (e.KeyCode == Keys.Down && _lb.SelectedIndex == _lb.Items.Count)))
    {
    _lb.SelectedIndex = -1;
    TextBoxText = _general_text;
    }
    else
    {
    TextBoxText = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    _lb_kd_first_top = _lb.SelectedIndex != 0;
    }
    if (e.KeyCode == Keys.Enter && _lb.SelectedIndex != -1)
    {
    _lb.Visible = false;
    this.Height = _tb.Height;
    _tb.Focus();
    }
    }
    //列表鼠标单击事件
    void _lb_Click(object sender, EventArgs e)
    {
    if (_lb.SelectedIndex != -1)
    {
    TextBoxText = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    }
    _lb.Visible = false;
    _tb.Focus();
    this.Height = _tb.Height;
    }

    复制代码 代码如下:
    //文本框按键事件
    void _tb_KeyDown(object sender, KeyEventArgs e)
    {
    if (_lb.Items.Count == 0||!_lb.Visible) return;
    bool _is_set = false;
    if (e.KeyCode == Keys.Up)
    {
    if (_lb.SelectedIndex <= 0)
    {
    _lb.SelectedIndex = -1;
    TextBoxText = _general_text;
    }
    else
    {
    _lb.SelectedIndex--;
    _is_set = true;
    }
    }
    else if (e.KeyCode == Keys.Down)
    {
    if (_lb.SelectedIndex == _lb.Items.Count - 1)
    {
    _lb.SelectedIndex = 0;
    _lb.SelectedIndex = -1;
    TextBoxText = _general_text;
    }
    else
    {
    _lb.SelectedIndex++;
    _is_set = true;
    }
    }
    else if (e.KeyCode == Keys.Enter)
    {
    _lb.Visible = false;
    this.Height = _tb.Height;
    _is_set = _lb.SelectedIndex != -1;
    }
    _lb_kd_first_top = _lb.SelectedIndex != 0;
    if (_is_set)
    {
    _text_lock = true;
    _tb.Text = ((DataRowView)_lb.SelectedItem)[ValueName].ToString();
    _tb.SelectionStart = _tb.Text.Length + 10;
    _tb.SelectionLength = 0;
    _text_lock = false;
    }
    }
    //文本框文本变更事件
    void _tb_TextChanged(object sender, EventArgs e)
    {
    if (_text_lock) return;
    _general_text = _tb.Text;
    _lb.Visible = true;
    _lb.Height = _lb.ItemHeight * (_itemCount+1);
    this.BringToFront();
    _lb.BringToFront();
    this.Height = _tb.Height + _lb.Height;
    DataTable temp_table = _dt_datasource.Clone();
    string filtStr = FormatStr(_tb.Text);
    DataRow [] rows = _dt_datasource.Select(string.Format(GetFilterStr(),CodeName,filtStr,_lb.DisplayMember));
    for (int i = 0; i < rows.Length&&i<_itemCount; i++)
    {
    temp_table.Rows.Add(rows[i].ItemArray);
    }
    _lb.DataSource = temp_table;
    if (_lb.Items.Count > 0) _lb.SelectedItem = _lb.Items[0];
    }

    复制代码 代码如下:
    /// <summary>
    /// 初始化控件
    /// </summary>
    private void InitialControls()
    {
    _lb_kd_first_top = true;
    _tb = new TextBox();
    _tb.Location = new Point(0, 0);
    _tb.Margin = new System.Windows.Forms.Padding(0);
    _tb.Width = this.Width;
    _tb.TextChanged += new EventHandler(_tb_TextChanged);
    _tb.KeyUp += new KeyEventHandler(_tb_KeyDown);
    _lb = new ListBox();
    _lb.Visible = false;
    _lb.Width = _tb.Width;
    _lb.Margin = new System.Windows.Forms.Padding(0);
    _lb.DisplayMember = ValueName;
    _lb.SelectionMode = SelectionMode.One;
    _lb.Location = new Point(0, _tb.Height);
    _lb.KeyUp += new KeyEventHandler(_lb_KeyDown);
    _lb.Click += new EventHandler(_lb_Click);
    this.Controls.Add(_tb);
    this.Controls.Add(_lb);
    this.Height = _tb.Height - 1;
    this.LostFocus += new EventHandler(AutoComplete_LostFocus);
    this.Leave += new EventHandler(AutoComplete_LostFocus);
    this.Load += new EventHandler(AutoComplete_Load);
    }
    /// <summary>
    /// 获取过滤格式字符串
    /// </summary>
    /// <returns></returns>
    private string GetFilterStr()
    {
    //未过滤注入的字符 ' ] %任意 *任意
    string filter = " {0} like '{1}%' and IsNull([{2}], ' ') <> ' ' ";
    if (_dt_datasource.Rows[0][CodeName].ToString().LastIndexOf(';') > -1)
    filter = " {0} like '%;{1}%' and IsNull([{2}],' ') <> ' ' ";
    return filter;
    }
    /// <summary>
    /// 过滤字符串中一些可能造成出错的字符
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    private string FormatStr(string str)
    {
    if (string.IsNullOrEmpty(str)) return string.Empty;
    str = str.Replace("[", "[[]").Replace("%", "[%]").Replace("*", "[*]").Replace("'", "''");
    if (CodeName == "code") str = str.Replace(" ", "");
    return str;
    }

    下面是使用控件的例子
    复制代码 代码如下:
    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;

    详细出处参考:http://www.jb51.net/article/33386.htm

  • 相关阅读:
    【PAT甲级】1063 Set Similarity (25 分)
    【PAT甲级】1062 Talent and Virtue (25 分)
    【PAT甲级】1061 Dating (20 分)
    Codeforces Global Round 5E(构造,思维)
    Codeforces Round #592 (Div. 2)G(模拟)
    POJ 刷题进程.1
    登录页面 (带遮罩层的) ---2017-04--5
    回答: 2017-03-19的关于css+div布局的疑问 2017-04-05
    关于js高度和宽度的获取 ----2017-03-29
    如何用写js弹出层 ----2017-03-29
  • 原文地址:https://www.cnblogs.com/xiaofengfeng/p/3488969.html
Copyright © 2011-2022 走看看