关于TextBox的AutoComplete功能断断续续搞了一段时间,之前写过几个类似的自定义控件,包括TextBox自带的,但是效果不是很好。刚好项目需要,结合原来的思路重新写了一个相对比较好用的版本。
废话不多说,直接贴代码吧。下拉的控件我用的DevExpress的GridControl,比较美观。可以根据自己的需要改成DataGridView或者ListView。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using DevExpress.XtraGrid; 10 using DevExpress.XtraGrid.Views.Grid; 11 12 namespace TestAutoComplete 13 { 14 public partial class AutoTextBoxNew : TextBox 15 { 16 private string[] _keys; 17 private SearchMode _searchMode; 18 private List<BaseItem> items = new List<BaseItem>(); 19 private GridView _view; 20 private GridControl _grid; 21 private int _gvWidth = 200; 22 private int _gvHeight = 200; 23 private DataTable _dtlData = null;//绑定的数据源 24 private Control _form; 25 private string _needValue; 26 private string _needName; 27 private bool _isSearch = true; 28 private bool _isShowAllData = false; 29 30 #region 属性 31 [TypeConverter(typeof(System.ComponentModel.CollectionConverter))] 32 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 33 [Category("样式")] 34 [Description("绑定列")] 35 public List<BaseItem> Items 36 { 37 get 38 { return items; } 39 } 40 41 [Category("样式")] 42 [Description("模糊查找关键字")] 43 public string[] SearchKey 44 { 45 get { return _keys;} 46 set { _keys = value; } 47 } 48 49 [Category("样式")] 50 [Description("赋值在文本框的tag里,对应数据源的字段名称")] 51 public string NeedValue 52 { 53 get { return _needValue; } 54 set { _needValue = value; } 55 } 56 57 [Category("样式")] 58 [Description("赋值在文本框上的内容,对应数据源的字段名称")] 59 public string NeedName 60 { 61 get { return _needName; } 62 set { _needName = value; } 63 } 64 65 [Category("样式")] 66 [Description("模糊查找的方式,有左模糊、右模糊、全模糊")] 67 public SearchMode SearchModel 68 { 69 get { return _searchMode; } 70 set 71 { 72 _searchMode = value; 73 } 74 } 75 76 [Category("样式")] 77 [Description("GridView宽度")] 78 public int GridViewWidth 79 { 80 get { return _gvWidth; } 81 set 82 { 83 _gvWidth = value; 84 } 85 } 86 87 [Category("样式")] 88 [Description("GridView高度")] 89 public int GridViewHeight 90 { 91 get { return _gvHeight; } 92 set 93 { 94 _gvHeight = value; 95 } 96 } 97 98 [Category("样式")] 99 [Description("当未输入查询条件时是否全显示数据")] 100 public bool IsShowAllData 101 { 102 get { return _isShowAllData; } 103 set 104 { 105 _isShowAllData = value; 106 } 107 } 108 109 #endregion 110 111 /// <summary> 112 /// 构造函数 113 /// </summary> 114 public AutoTextBoxNew() 115 { 116 InitializeComponent(); 117 _grid = new GridControl(); 118 } 119 120 /// <summary> 121 /// 初始化 122 /// </summary> 123 /// <param name="dtlSource"></param> 124 public void Init(DataTable dtlSource) 125 { 126 _dtlData = dtlSource; 127 initListView(); 128 } 129 130 /// <summary> 131 /// 初始化GridView 132 /// </summary> 133 private void initListView() 134 { 135 if (items != null) 136 { 137 try 138 { 139 _view = new GridView(); 140 _view.OptionsView.ShowGroupPanel = false; 141 _view.OptionsBehavior.Editable = false; 142 _view.OptionsView.ColumnAutoWidth = false; 143 _grid.KeyDown += new KeyEventHandler(_grid_KeyDown); 144 _grid.MouseDoubleClick += new MouseEventHandler(_grid_MouseDoubleClick); 145 _grid.Leave += new EventHandler(_grid_Leave); 146 foreach (BaseItem item in items) 147 { 148 DevExpress.XtraGrid.Columns.GridColumn col = new DevExpress.XtraGrid.Columns.GridColumn(); 149 150 col.FieldName = item.FieldCode; 151 col.Caption = item.DisplayName; 152 col.Width = item.ColumnWidth == 0 ? 100 : item.ColumnWidth; 153 col.Visible = true; 154 _view.Columns.Add(col); 155 } 156 _grid.MainView = _view; 157 _grid.Width = _gvWidth; 158 _grid.Height = _gvHeight; 159 _form = this.Parent; 160 while (true) 161 { 162 if (_form.Parent == null) break; 163 _form = _form.Parent; 164 } 165 _grid.Location = _form.PointToClient(this.Parent.PointToScreen(new Point(this.Left, this.Top + this.Height + 3))); 166 _form.Controls.Add(_grid); 167 _grid.Visible = false; 168 } 169 catch 170 { 171 172 } 173 } 174 } 175 176 /// <summary> 177 /// GridView焦点离开 178 /// </summary> 179 /// <param name="sender"></param> 180 /// <param name="e"></param> 181 public void _grid_Leave(object sender, EventArgs e) 182 { 183 if (!this.Focused) 184 { 185 _grid.Visible = false; 186 } 187 } 188 189 /// <summary> 190 /// GridView双击事件,赋值 191 /// </summary> 192 /// <param name="sender"></param> 193 /// <param name="e"></param> 194 public void _grid_MouseDoubleClick(object sender, MouseEventArgs e) 195 { 196 if (_view.FocusedRowHandle >= 0) 197 { 198 _isSearch = false; 199 this.Tag = _view.GetFocusedRowCellValue(_needValue).ToString(); 200 this.Text = _view.GetFocusedRowCellValue(_needName).ToString(); 201 _grid.Visible = false; 202 } 203 } 204 205 /// <summary> 206 /// GridView回车事件,赋值 207 /// </summary> 208 /// <param name="sender"></param> 209 /// <param name="e"></param> 210 public void _grid_KeyDown(object sender, KeyEventArgs e) 211 { 212 if (e.KeyCode == Keys.Enter) 213 { 214 if (_view.FocusedRowHandle >= 0) 215 { 216 _isSearch = false; 217 this.Tag = _view.GetFocusedRowCellValue(_needValue).ToString(); 218 this.Text = _view.GetFocusedRowCellValue(_needName).ToString(); 219 _grid.Visible = false; 220 } 221 } 222 } 223 224 protected override void OnPaint(PaintEventArgs pe) 225 { 226 base.OnPaint(pe); 227 } 228 229 protected override void OnTextChanged(EventArgs e) 230 { 231 if (this.Text != "") 232 { 233 if (_isSearch) 234 { 235 DataTable dt = Search(this.Text); 236 _grid.DataSource = dt; 237 _grid.Visible = true; 238 _grid.BringToFront(); 239 } 240 else 241 { 242 _isSearch = true; 243 } 244 245 } 246 else 247 { 248 if (_isShowAllData) 249 { 250 _grid.DataSource = _dtlData; 251 _grid.Visible = true; 252 _grid.BringToFront(); 253 } 254 else 255 { 256 _grid.Visible = false; 257 } 258 } 259 base.OnTextChanged(e); 260 } 261 262 protected override void OnKeyDown(KeyEventArgs e) 263 { 264 if (e.KeyCode == Keys.Down) 265 { 266 _grid.Focus(); 267 } 268 else if (e.KeyCode == Keys.Enter) 269 { 270 if (_grid.DataSource != null) 271 { 272 _isSearch = false; 273 this.Tag = _view.GetRowCellValue(0, _needValue).ToString(); 274 this.Text = _view.GetRowCellValue(0, _needName).ToString(); 275 _grid.Visible = false; 276 } 277 } 278 base.OnKeyDown(e); 279 } 280 281 /// <summary> 282 /// 检索 283 /// </summary> 284 /// <param name="keyvalue"></param> 285 /// <returns></returns> 286 private DataTable Search(string keyvalue) 287 { 288 DataTable dtlReturn = null; 289 if (_dtlData != null && _keys.Length > 0) 290 { 291 string filters = ""; 292 foreach (string str in _keys) 293 { 294 switch (_searchMode) 295 { 296 case SearchMode.Left: 297 filters += "or " + str + " like'%" + keyvalue + "' "; 298 break; 299 case SearchMode.Right: 300 filters += "or " + str + " like'" + keyvalue + "%' "; 301 break; 302 case SearchMode.All: 303 filters += "or " + str + " like'%" + keyvalue + "%' "; 304 break; 305 } 306 } 307 filters = filters.Substring(2, filters.Length - 2); 308 DataRow[] dr = _dtlData.Select(filters); 309 if (dr.Length > 0) 310 { 311 dtlReturn = dr.CopyToDataTable(); 312 } 313 } 314 return dtlReturn; 315 } 316 317 /// <summary> 318 /// 焦点离开隐藏起来 319 /// </summary> 320 /// <param name="e"></param> 321 protected override void OnLeave(EventArgs e) 322 { 323 if (!_grid.IsFocused) 324 { 325 _grid.Visible = false; 326 } 327 base.OnLeave(e); 328 } 329 330 } 331 332 public class BaseItem 333 { 334 public string DisplayName 335 { get; set; } 336 public string FieldCode 337 { get; set; } 338 public int ColumnWidth 339 { get; set; } 340 } 341 342 public enum SearchMode { Left, Right, All } 343 }View Code
调用比较简单,需要配置一些属性,如图:
Items主要设置需要显示哪些列,NeedName与NeedValue必须配置一下,赋值的时候需要用到。
最后调用一下初始化的方法把数据源传入就OK了
autoTextBoxNew1.Init(ds.Tables[0]);
看看效果图: