前言
最进在做一个医院的体检软件,用的是C#中的WinForm开发,当中用到了智能提示功能,其中Web的开发比较方便,提供了专门的ajax智能提示自动不全控件AutoComplete,但是在WinForm开发中,没有这样的控件,自己只有动手做一个这样的控件了,查找了一些资料和自己努力,找到了解决办法。下面就以起始站和到站在输入站名的汉字首字母进行智能提示汉字站名为例帮助说明如何来实现自动补全。如下图:
这功能在WinForm里用什么控件来实现呢?
一、自带控件
WinForm里面的ComBoBox 和TextBox 其实是有自带的自动补全功能的,我们只需要将设置相应的属性:
1、将 AutoCompleteSource 属性设置为 ListItems 或 CustomerSource (textbox 没有 ListItems)
2、设置 AutoCompleteMode 自动完成样式属性设置,有三值 Suggest(显示相关下拉)、append(自动补全相关)、suggestappend(前两者的结合),这个可以自行试验下。
3、然后设置 绑定 控件的 DataSource 或 AutoCompleteCustomSource。
当AutoCompleteSource属性设置的是 CustomerSource 的时候我们需要绑定 AutoCompleteCustomSource属性的值,值为一个string类型的数组:
this.cbbEndStation.AutoCompleteCustomSource.AddRange(new string[] { "站点1", "站点2", "站点3", "站点4" });
这样ComBoBox 和 TextBox 就有输入提示功能了。至此,不知道大家有没有发现问题,这里绑定的数据只有 显示的值,而没有 实际的值,一般像这种控件,我们都是有一个显示值和一个实际值的。有人可能会说,使用ComBoBox 控件,然后将AutoCompleteSource设置为ListItems,提示的就是DataSource里的值了,而DataSource是可以绑定 集合,设置DisplayMember和ValueMember的。是的,这样可以实现自动提示,并且也能在选中提示的某项时,取到显示的值和实际值。但是这种方式至少有两个缺点:
1、像购票的站点这种,数据量很大,有2k多条吧,你一次全绑定到ComboBox上?数据量太大,它没有提供相应的事件来过滤数据。
2、多种搜索方式怎么办?中文、拼音、实际值、都是是可以用来做输入提示的关键字的。
其实以上两点就是应为 没有提供相应的事件来处理 “搜索”。
二、TextBox+ListBox 自定义AutoComplete
其实我可以用 TextBox来获得用户的输入,然后动态控制ListBox。下面就按我做的思路一步步来实现一个自定义AutoComplete。
1、监听 textbox的 keyUp事件,获得用户输入
/// <summary> /// 站点文本框 键盘按下松开事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void txtStation_KeyUp(object sender, KeyEventArgs e) { TextBox eObj = sender as TextBox; //事件源对象 txtStation_Name = eObj; //当前事件出发对象 if (eObj.Name == "txtStation_S_Name") { txtStation_Value = this.txtStation_S_Value; //保存值的textbox ltb_Stations = this.lb_Start_Stations; //始发站 展示数据的 } else { //到站 控件 txtStation_Value = this.txtStation_E_Value; //保存值的textbox ltb_Stations = this.lb_End_Stations; //始发站 展示数据的 } //上下左右 if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Left) { if (ltb_Stations.SelectedIndex > 0) ltb_Stations.SelectedIndex--; } else if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Right) { if (ltb_Stations.SelectedIndex < ltb_Stations.Items.Count - 1) ltb_Stations.SelectedIndex++; } //回车 else if (e.KeyCode == Keys.Enter) { StationInfo info = ltb_Stations.SelectedItem as StationInfo; txtStation_Name.Text = info.StationName_CN; txtStation_Value.Text = info.StationValue; ltb_Stations.Visible = false; } else { if (txtStation_Name.Text != "") { IList<StationInfo> dataSource = StationInfo.GetStations(txtStation_Name.Text.Trim()); if (dataSource.Count > 0) { ltb_Stations.DataSource = dataSource; ltb_Stations.DisplayMember = "StationName_CN"; ltb_Stations.ValueMember = "StationValue"; ltb_Stations.Visible = true; } else ltb_Stations.Visible = false; } else { ltb_Stations.Visible = false; } } txtStation_Name.Select(txtStation_Name.Text.Length, 1); //光标定位到文本框最后 }
2、监听 ListBox 控件的点击事件
/// <summary> /// 展示站点列表的listbox的点击事件,为了给textbox赋值 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ListBox_StationDatas_Click(object sender, EventArgs e) { ListBox eObj = sender as ListBox; StationInfo info = eObj.SelectedItem as StationInfo; txtStation_Name.Text = info.StationName_CN; txtStation_Value.Text = info.StationValue; eObj.Visible = false; txtStation_Name.Select(txtStation_Name.Text.Length, 1); //光标定位到最后 }
3、监听 ListBox 控件的鼠标移动事件
/// <summary> /// 展示站点列表的listbox, 鼠标在该控件上移动事件, /// 为了鼠标移动选项 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ListBox_StationDatas_MouseMove(object sender, MouseEventArgs e) { ListBox eObj = sender as ListBox; eObj.SelectedIndex = eObj.IndexFromPoint(e.Location); }
以上三步就可以完成一个自定义 AutoComplete的功能了,为什么要叫自定义呢?因为我们在 监听 TextBox 的输入时,可以自定义搜索规则,还有我们可以将ListBox换成 DataGridView都是可以的,灵活性很大,只要按这个思路来就可以。
三、一些第三方控件
当然网络上也有一些非常好的类似AutoComplete的第三方控件,这里我就不一一列出来了,因为我没有找到合适的,呵呵!如果有人用过好的,欢迎在评论中分享,谢谢!
最后附上Demo的源码:点击AutoCompleteDemo.rar下载!