如何实现WPF TextBox仅允许编辑当前行,禁止修改历史行
解决WPF计算器仅允许编辑最后一行的问题
针对你的WPF计算器需求,要禁止用户修改历史行、仅允许编辑最后一行,可以通过以下几个关键步骤实现:
1. 限制光标位置,强制锁定到最后一行
添加SelectionChanged事件处理,确保用户无法将光标移动到最后一行之前:
private void displayText_SelectionChanged(object sender, RoutedEventArgs e) { if (displayText.LineCount <= 1) return; // 获取最后一行的起始字符索引 int lastLineStartIndex = displayText.GetCharacterIndexFromLineIndex(displayText.LineCount - 1); // 如果光标起始位置在历史行范围内,强制移到最后一行末尾 if (displayText.SelectionStart < lastLineStartIndex) { displayText.Select(displayText.Text.Length, 0); } }
2. 拦截文本修改,禁止修改历史行
修改原有的TextBox_TextChanged事件,检测是否有针对历史行的修改,若有则撤销:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { maxLines = displayText.LineCount; if(maxLines > 0) { lastLine = displayText.GetLineText(maxLines - 1); } if (displayText.LineCount <= 1) return; int lastLineStartIndex = displayText.GetCharacterIndexFromLineIndex(displayText.LineCount - 1); bool hasHistoryEdit = false; // 检查所有文本变更是否涉及历史行 foreach (var change in e.Changes) { if (change.Offset < lastLineStartIndex) { hasHistoryEdit = true; break; } } if (hasHistoryEdit) { // 临时解绑事件避免递归触发 displayText.TextChanged -= TextBox_TextChanged; // 撤销所有历史行的修改 foreach (var change in e.Changes.Reverse()) { displayText.Text = displayText.Text.Remove(change.Offset, change.AddedLength); // 恢复被删除的字符 if (change.RemovedLength > 0) { string restoredText = displayText.Text.Substring(change.Offset, change.RemovedLength); displayText.Text = displayText.Text.Insert(change.Offset, restoredText); } } displayText.TextChanged += TextBox_TextChanged; // 重置光标到最后一行末尾 displayText.Select(displayText.Text.Length, 0); } }
3. 拦截鼠标点击,禁止点击历史行
添加PreviewMouseDown事件处理,防止用户通过鼠标点击选中历史行:
private void displayText_PreviewMouseDown(object sender, MouseButtonEventArgs e) { if (displayText.LineCount <= 1) return; var clickPoint = e.GetPosition(displayText); int clickedCharIndex = displayText.GetCharacterIndexFromPoint(clickPoint, true); int lastLineStartIndex = displayText.GetCharacterIndexFromLineIndex(displayText.LineCount - 1); // 如果点击位置在历史行范围内,阻止默认行为并重置光标 if (clickedCharIndex < lastLineStartIndex) { e.Handled = true; displayText.Select(displayText.Text.Length, 0); } }
4. 绑定事件到TextBox
在你的XAML文件中,给displayText控件添加这三个事件绑定:
<TextBox x:Name="displayText" TextChanged="TextBox_TextChanged" SelectionChanged="displayText_SelectionChanged" PreviewMouseDown="displayText_PreviewMouseDown" KeyDown="TextBox_KeyDown" />
补充说明
- 上述代码通过三重拦截(光标位置、文本修改、鼠标点击)确保历史行无法被编辑
- 在
TextChanged的撤销逻辑中,简化了恢复操作,你可以根据实际需求结合历史文本快照做更精准的恢复 - 原有的键盘事件逻辑可以保留,因为光标已经被锁定在最后一行,键盘输入只会作用于当前行
内容的提问来源于stack exchange,提问作者Theo 17
相关产品推荐
相关产品推荐

