You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 19:15:31