如何在C# Windows Forms中实现垂直文本选择与多行同步编辑?
在C# Windows Forms中实现垂直文本选择与多行同步输入
要实现类似Notepad++的垂直选择和多行同步输入功能,WinForms默认的TextBox无法满足需求,我们可以基于RichTextBox控件自定义逻辑来实现。以下是具体步骤和代码示例:
1. 准备基础控件
在Form中添加一个RichTextBox控件(命名为rtbEditor),并设置以下属性:
Multiline = trueScrollBars = RichTextBoxScrollBars.BothFont = new Font("Consolas", 10f)(可选,等宽字体更适配垂直选择场景)
2. 实现Ctrl+Shift方向键的垂直选择
首先定义两个私有变量记录选择状态:
private Point _verticalSelectStart; private bool _isVerticalSelecting = false;
为rtbEditor绑定KeyDown事件,处理Ctrl+Shift+方向键的组合操作:
private void rtbEditor_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.Shift) { if (!_isVerticalSelecting) { // 记录垂直选择的起始位置(字符索引+行号) int startCharIndex = rtbEditor.SelectionStart; int startLine = rtbEditor.GetLineFromCharIndex(startCharIndex); _verticalSelectStart = new Point(startCharIndex, startLine); _isVerticalSelecting = true; } // 获取当前光标所在的行和列 int currentCharIndex = rtbEditor.SelectionStart; int currentLine = rtbEditor.GetLineFromCharIndex(currentCharIndex); int currentCol = currentCharIndex - rtbEditor.GetFirstCharIndexFromLine(currentLine); // 根据方向键计算目标行/列 int targetLine = currentLine; int targetCol = currentCol; switch (e.KeyCode) { case Keys.Up: targetLine = Math.Max(0, currentLine - 1); break; case Keys.Down: targetLine = Math.Min(rtbEditor.Lines.Length - 1, currentLine + 1); break; case Keys.Left: targetCol = Math.Max(0, currentCol - 1); break; case Keys.Right: targetCol = Math.Min(rtbEditor.Lines[currentLine].Length, currentCol + 1); break; } // 计算垂直选择的范围:起始行/列到目标行/列 int startLine = Math.Min(_verticalSelectStart.Y, targetLine); int endLine = Math.Max(_verticalSelectStart.Y, targetLine); int startCol = Math.Min(_verticalSelectStart.X - rtbEditor.GetFirstCharIndexFromLine(_verticalSelectStart.Y), targetCol); int endCol = Math.Max(_verticalSelectStart.X - rtbEditor.GetFirstCharIndexFromLine(_verticalSelectStart.Y), targetCol); // 逐行选中对应区域 rtbEditor.SelectionStart = 0; rtbEditor.SelectionLength = 0; rtbEditor.SelectionBackColor = SystemColors.Window; // 清除之前的选择 for (int line = startLine; line <= endLine; line++) { int lineStartChar = rtbEditor.GetFirstCharIndexFromLine(line); int selectStart = lineStartChar + startCol; int selectLength = endCol - startCol; // 处理行长度不足的情况,避免越界 if (selectStart + selectLength > lineStartChar + rtbEditor.Lines[line].Length) { selectLength = (lineStartChar + rtbEditor.Lines[line].Length) - selectStart; } if (selectLength > 0) { rtbEditor.Select(selectStart, selectLength); rtbEditor.SelectionBackColor = SystemColors.Highlight; rtbEditor.SelectionColor = SystemColors.HighlightText; } } e.Handled = true; // 阻止默认事件 } else { _isVerticalSelecting = false; // 结束垂直选择模式 } }
3. 实现多行同步输入
为rtbEditor绑定KeyPress事件,处理垂直选择状态下的输入逻辑:
private void rtbEditor_KeyPress(object sender, KeyPressEventArgs e) { // 判断是否处于垂直选择状态 bool isVerticalSelection = false; int selStart = rtbEditor.SelectionStart; int selLength = rtbEditor.SelectionLength; int startLine = rtbEditor.GetLineFromCharIndex(selStart); int endLine = rtbEditor.GetLineFromCharIndex(selStart + selLength - 1); if (startLine != endLine) { // 验证每行选中的长度是否一致(垂直选择的特征) int lineCount = endLine - startLine + 1; int singleLineSelLength = selLength / lineCount; isVerticalSelection = true; for (int line = startLine; line <= endLine; line++) { int lineStartChar = rtbEditor.GetFirstCharIndexFromLine(line); int lineSelStart = lineStartChar + (selStart - rtbEditor.GetFirstCharIndexFromLine(startLine)); int actualLineSelLength = (line == endLine) ? selStart + selLength - lineSelStart : rtbEditor.GetFirstCharIndexFromLine(line + 1) - lineSelStart; if (actualLineSelLength != singleLineSelLength) { isVerticalSelection = false; break; } } } if (isVerticalSelection && !char.IsControl(e.KeyChar)) { int lineCount = endLine - startLine + 1; int singleLineSelLength = selLength / lineCount; int colStart = selStart - rtbEditor.GetFirstCharIndexFromLine(startLine); // 批量修改文本,避免频繁刷新 rtbEditor.BeginUpdate(); rtbEditor.SelectionLength = 0; for (int line = startLine; line <= endLine; line++) { int lineStartChar = rtbEditor.GetFirstCharIndexFromLine(line); int targetPos = lineStartChar + colStart; // 删除当前行的选中内容 if (singleLineSelLength > 0) { rtbEditor.Select(targetPos, singleLineSelLength); rtbEditor.SelectedText = ""; } // 插入新输入的字符 rtbEditor.Select(targetPos, 0); rtbEditor.SelectedText = e.KeyChar.ToString(); } // 重新设置垂直选择范围 rtbEditor.Select(selStart, lineCount * 1); rtbEditor.EndUpdate(); e.Handled = true; // 阻止默认输入逻辑 } }
4. 扩展优化(可选)
- 添加
Backspace和Delete键的处理逻辑,实现垂直选择内容的批量删除 - 支持鼠标垂直选择(按住Alt键拖动鼠标),需处理
MouseDown、MouseMove事件计算选择区域
内容的提问来源于stack exchange,提问作者Moraban
相关产品推荐
相关产品推荐

