欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WinForm 自动完成控件实例代码简析

程序员文章站 2023-11-27 09:00:16
在web的应用方面有js的插件实现自动完成(或叫智能提示)功能,但在winform窗体应用方面就没那么好了。textbox控件本身是提供了一个自动提示功能,只要用上这三个属...
在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}], ' ') <> ' ')来筛选出合适的备选文本内容,以下则是控件的代码:
复制代码 代码如下:

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;