Autocomplete

/* * Made by Lonami, the 01/12/2014 at 18:30 * (C) LonamiWebs */ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; public class AutoComplete { #region Private variables readonly TextBox TB; readonly Form form = new Form { Size = new Size(120, 60), FormBorderStyle = FormBorderStyle.None, TopMost = true }; readonly ListBox listbox = new ListBox { Dock = DockStyle.Fill }; bool working; #endregion #region Public variables public int Width { get { return form.Size.Width; } set { form.Size = new Size(value, form.Size.Height); } } public int Height { get { return form.Size.Height; } set { form.Size = new Size(form.Size.Width, value); } } public Point Offset = new Point(10, 10); public List<Keys> AutocompleteKeys = new List<Keys> { Keys.Enter, Keys.Tab, Keys.Space, Keys.OemPeriod }; List<string> Suggestions = new List<string>(); public List<string> GetSuggestions() { return Suggestions; } public void AddSuggestion(string suggestion) { if (!Suggestions.Contains(suggestion)) Suggestions.Add(suggestion); } public void AddSuggestions(IEnumerable<string> suggestions) { foreach (var suggestion in suggestions) AddSuggestion(suggestion); } public int MaximumSuggestions = 50; #endregion #region Initialize public AutoComplete(TextBox textboxToAsign) { TB = textboxToAsign; TB.KeyDown += textboxToAsign_KeyDown; TB.KeyUp += (s, e) => RefreshSuggestList(true); TB.Click += (s, e) => HideSuggests(); TB.LostFocus += TB_LostFocus; TB.LocationChanged += (s, e) => RefreshLocation(); var parent = TB.Parent; while (parent != null) { parent.LocationChanged += (s, e) => RefreshLocation(); parent = parent.Parent; } listbox.MouseEnter += (s, e) => working = true; listbox.MouseLeave += (s, e) => working = false; listbox.MouseDoubleClick += (s, e) => SelectSuggestion(); form.Controls.Add(listbox); form.GotFocus += (s, e) => TB.Focus(); } #endregion #region Show/hide form void textboxToAsign_KeyDown(object sender, KeyEventArgs e) { working = true; if (e.KeyCode == Keys.Up) { HandleKEA(ref e); MoveUp(); } else if (e.KeyCode == Keys.Down) { HandleKEA(ref e); MoveDown(); } else if (AutocompleteKeys.Contains(e.KeyCode)) { HandleKEA(ref e); SelectSuggestion(e.KeyCode); } else if (!e.Control && IsLetterOrDigit(e.KeyCode, e.Shift)) { RefreshSuggestList(); ShowSuggests(); } else HideSuggests(); working = false; } void HideSuggests() { form.Hide(); } void ShowSuggests() { if (listbox.Items.Count > 0) { form.Show(); RefreshLocation(); TB.Focus(); } else HideSuggests(); } void RefreshLocation() { Point p = TB.GetPositionFromCharIndex(TB.SelectionStart > 0 ? TB.SelectionStart - 1 : 0); form.Location = TB.PointToScreen(new Point(p.X + Offset.X, p.Y + Offset.Y)); } void TB_LostFocus(object sender, EventArgs e) { if (!working) HideSuggests(); } #endregion #region Suggestions void RefreshSuggestList(bool keepindex = false) { int lindex = keepindex ? listbox.SelectedIndex : 0; listbox.BeginUpdate(); listbox.Items.Clear(); string[] w = GetSuggestions(GetLastWord()); string[] x = null; if (w.Length > MaximumSuggestions) { x = new string[MaximumSuggestions]; for (int i = 0; i < MaximumSuggestions; i++) x[i] = w[i]; } listbox.Items.AddRange(x ?? w); if (listbox.Items.Count > lindex) listbox.SelectedIndex = lindex; else if (listbox.Items.Count > 0) listbox.SelectedIndex = 0; else { listbox.SelectedIndex = -1; HideSuggests(); } listbox.EndUpdate(); } void MoveDown() { if (listbox.SelectedIndex + 1 < listbox.Items.Count) listbox.SelectedIndex++; } void MoveUp() { if (listbox.SelectedIndex > 0) listbox.SelectedIndex--; } void SelectSuggestion(Keys key = Keys.Enter) { if (!form.Visible) return; working = true; int lindex = TB.SelectionStart; if (listbox.SelectedIndex > -1) { string wrd = listbox.SelectedItem.ToString(); switch (key) { case Keys.Space: wrd += " "; break; case Keys.OemPeriod: wrd += "."; break; } lindex = ReplaceLastWord(wrd); } TB.Focus(); TB.SelectionStart = lindex; TB.ScrollToCaret(); HideSuggests(); working = false; } string[] GetSuggestions(string startingWord) { return Suggestions.Where(x => x.StartsWith(startingWord, StringComparison.InvariantCultureIgnoreCase)).ToArray(); } #endregion #region Utils string GetLastWord() { int i = TB.SelectionStart, j = i--; while (i > 0) { if (Char.IsLetterOrDigit(TB.Text[i])) i--; else { i++; break; } } return i < 0 ? "" : TB.Text.Substring(i, j - i); } int ReplaceLastWord(string replacewith) { int i = TB.SelectionStart, j = i--; while (i > 0) { if (Char.IsLetterOrDigit(TB.Text[i])) i--; else { i++; break; } } TB.Text = i < 0 ? "" : TB.Text.Substring(0, i) + replacewith + TB.Text.Substring(j, TB.Text.Length - j); int alreadytyped = j - i; return j + replacewith.Length - alreadytyped; } bool IsLetterOrDigit(Keys key, bool shift) { int k = (int)key; return (k > 64 && k < 91) || (!shift && (k > 47 && k < 58)); } void HandleKEA(ref KeyEventArgs e) { e.Handled = e.SuppressKeyPress = form.Visible; } #endregion }
If you want to add Autocomplete feature to any multiline TextBox, this is your piece of code!

Be the first to comment

You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.