C#实现智能提示输入,并增色显示
实现一个智能下拉提示输入的功能,使用RichTextBox实现,结合了ListBox 实现特定字符提示输入选项 并对关键选项标记颜色突出显示
效果如下:

代码如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;namespace SmartBox
{public class SmartRichTextBox : RichTextBox{private ListBox _suggestionList;private List<string> _variableList;private string _triggerChar = "#";private Form _parentForm;// 语法高亮颜色private Color _variableColor = Color.Blue;private Color _normalColor = Color.Black;// 用于防止重入的标记private bool _isHighlighting = false;public SmartRichTextBox(){_variableList = new List<string>{"username", "email", "phone", "address","date", "time", "user_id", "department"};InitializeSuggestionList();this.KeyDown += SmartRichTextBox_KeyDown;this.KeyUp += SmartRichTextBox_KeyUp;this.TextChanged += SmartRichTextBox_TextChanged;this.LostFocus += SmartRichTextBox_LostFocus;this.SelectionChanged += SmartRichTextBox_SelectionChanged;// 设置默认字体和颜色this.Font = new Font("Microsoft Sans Serif", 9f);this.ForeColor = _normalColor;}public List<string> VariableList{get { return _variableList; }set { _variableList = value; }}public string TriggerChar{get { return _triggerChar; }set { _triggerChar = value; }}public Color VariableColor{get { return _variableColor; }set { _variableColor = value; }}private void InitializeSuggestionList(){_suggestionList = new ListBox{Visible = false,Width = this.Width,Height = 120,Font = this.Font,BorderStyle = BorderStyle.FixedSingle};_suggestionList.Click += SuggestionList_Click;_suggestionList.KeyDown += SuggestionList_KeyDown;_suggestionList.MouseMove += SuggestionList_MouseMove;}protected override void OnParentChanged(EventArgs e){base.OnParentChanged(e);if (this.Parent != null){_parentForm = this.FindForm();if (_parentForm != null){_parentForm.Controls.Add(_suggestionList);_suggestionList.BringToFront();}}}protected override void OnSizeChanged(EventArgs e){base.OnSizeChanged(e);if (_suggestionList != null){_suggestionList.Width = this.Width;}}#region 事件处理private void SmartRichTextBox_KeyUp(object sender, KeyEventArgs e){if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey)return;ShowSuggestions();}private void SmartRichTextBox_KeyDown(object sender, KeyEventArgs e){if (!_suggestionList.Visible)return;switch (e.KeyCode){case Keys.Down:if (_suggestionList.Items.Count > 0){_suggestionList.SelectedIndex = 0;_suggestionList.Focus();}e.Handled = true;break;case Keys.Enter:ApplySuggestion();e.Handled = true;break;case Keys.Escape:HideSuggestions();e.Handled = true;break;}}private void SuggestionList_KeyDown(object sender, KeyEventArgs e){switch (e.KeyCode){case Keys.Enter:ApplySuggestion();e.Handled = true;break;case Keys.Escape:HideSuggestions();this.Focus();e.Handled = true;break;case Keys.Up:if (_suggestionList.SelectedIndex == 0){this.Focus();e.Handled = true;}break;}}private void SuggestionList_Click(object sender, EventArgs e){ApplySuggestion();}private void SuggestionList_MouseMove(object sender, MouseEventArgs e){// 鼠标悬停时高亮项int index = _suggestionList.IndexFromPoint(e.Location);if (index >= 0){_suggestionList.SelectedIndex = index;}}private void SmartRichTextBox_SelectionChanged(object sender, EventArgs e){// 选择改变时隐藏建议列表if (_suggestionList.Visible){HideSuggestions();}}private void SmartRichTextBox_LostFocus(object sender, EventArgs e){// 延迟隐藏,以便点击下拉列表BeginInvoke(new Action(() =>{if (!_suggestionList.Focused && !this.Focused){HideSuggestions();}}));}#endregion#region 语法高亮功能private void SmartRichTextBox_TextChanged(object sender, EventArgs e){if (!_isHighlighting){ApplySyntaxHighlighting();}}/// <summary>/// 应用语法高亮/// </summary>private void ApplySyntaxHighlighting(){_isHighlighting = true;try{// 保存当前选择位置和颜色int currentSelectionStart = this.SelectionStart;int currentSelectionLength = this.SelectionLength;Color currentSelectionColor = this.SelectionColor;// 首先重置所有文本为默认颜色this.SelectAll();this.SelectionColor = _normalColor;this.DeselectAll();// 高亮所有以#开头的变量HighlightVariables();// 恢复选择位置this.SelectionStart = currentSelectionStart;this.SelectionLength = currentSelectionLength;this.SelectionColor = currentSelectionColor;}finally{_isHighlighting = false;}}/// <summary>/// 高亮变量/// </summary>private void HighlightVariables(){string text = this.Text;// 使用正则表达式匹配以#开头的变量// 匹配模式:以#开头,后面跟着字母、数字、下划线,直到遇到空格或标点string pattern = @"#\w+";var matches = Regex.Matches(text, pattern);foreach (Match match in matches){// 检查匹配的变量是否在变量列表中(去掉#号)string variableName = match.Value.Substring(1); // 去掉#号if (_variableList.Contains(variableName, StringComparer.OrdinalIgnoreCase)){this.Select(match.Index, match.Length);this.SelectionColor = _variableColor;}}}/// <summary>/// 手动刷新高亮(在变量列表改变后调用)/// </summary>public void RefreshHighlighting(){ApplySyntaxHighlighting();}#endregion#region 下拉建议功能private void ShowSuggestions(){string text = this.Text;int cursorPos = this.SelectionStart;// 查找触发字符的位置int triggerIndex = text.LastIndexOf(_triggerChar, cursorPos - 1);if (triggerIndex >= 0){// 检查#号后面是否已经有空格或其他分隔符bool hasSpaceAfterTrigger = false;for (int i = triggerIndex + 1; i < cursorPos; i++){if (char.IsWhiteSpace(text[i]) || text[i] == '.' || text[i] == ',' || text[i] == ';'){hasSpaceAfterTrigger = true;break;}}if (!hasSpaceAfterTrigger){string searchText = text.Substring(triggerIndex + 1, cursorPos - triggerIndex - 1);var matches = _variableList.Where(v => v.StartsWith(searchText, StringComparison.OrdinalIgnoreCase)).ToList();if (matches.Count > 0){_suggestionList.Items.Clear();foreach (var match in matches){_suggestionList.Items.Add(match);}// 定位下拉列表Point location = this.Location;Control parent = this.Parent;while (parent != null && !(parent is Form)){location.Offset(parent.Location.X, parent.Location.Y);parent = parent.Parent;}_suggestionList.Location = new Point(location.X, location.Y + this.Height);_suggestionList.Visible = true;_suggestionList.BringToFront();if (_suggestionList.Items.Count > 0){_suggestionList.SelectedIndex = 0;}return;}}}HideSuggestions();}private void HideSuggestions(){_suggestionList.Visible = false;}private void ApplySuggestion(){if (_suggestionList.SelectedItem != null){string selectedVar = _suggestionList.SelectedItem.ToString();string text = this.Text;int cursorPos = this.SelectionStart;// 找到最后一个触发字符的位置int triggerIndex = text.LastIndexOf(_triggerChar, cursorPos - 1);if (triggerIndex >= 0){// 替换从触发字符到当前位置的文本string newText = text.Substring(0, triggerIndex) +_triggerChar + selectedVar +text.Substring(cursorPos);this.Text = newText;this.SelectionStart = triggerIndex + _triggerChar.Length + selectedVar.Length;// 应用语法高亮ApplySyntaxHighlighting();}HideSuggestions();this.Focus();}}#endregion#region 公共方法/// <summary>/// 添加变量到列表/// </summary>public void AddVariable(string variableName){if (!_variableList.Contains(variableName, StringComparer.OrdinalIgnoreCase)){_variableList.Add(variableName);RefreshHighlighting();}}/// <summary>/// 从列表中移除变量/// </summary>public void RemoveVariable(string variableName){_variableList.RemoveAll(v => v.Equals(variableName, StringComparison.OrdinalIgnoreCase));RefreshHighlighting();}/// <summary>/// 清空所有变量/// </summary>public void ClearVariables(){_variableList.Clear();RefreshHighlighting();}/// <summary>/// 获取所有高亮的变量(不包含#号)/// </summary>public List<string> GetHighlightedVariables(){var variables = new List<string>();string text = this.Text;string pattern = @"#\w+";var matches = Regex.Matches(text, pattern);foreach (Match match in matches){string variableName = match.Value.Substring(1);//判断不区分大小写if (_variableList.Contains(variableName, StringComparer.OrdinalIgnoreCase)){variables.Add(variableName);}}return variables.Distinct().ToList();}#endregion#region 重写方法protected override void OnTextChanged(EventArgs e){// 确保基类处理完成后再进行高亮base.OnTextChanged(e);}protected override void OnFontChanged(EventArgs e){base.OnFontChanged(e);if (_suggestionList != null){_suggestionList.Font = this.Font;}}#endregion}
}
