WPF MVVM项目RichTextBox非均质选中文本应用下划线/删除线偏移求助
问题根因
你遇到的格式偏移问题核心是4个逻辑错误导致的:
- TextPointer偏移失效:循环中每次给单个字符应用格式时,RichTextBox会自动拆分原有Run节点,文档逻辑结构发生变化,
GetPositionAtOffset(1)无法正确指向原选区内的下一个字符,遍历越靠后偏移量越大。 - 状态判断逻辑不合理:仅取选中区域第一个字符的装饰线状态作为整个选区的切换依据,不符合常规富文本编辑器交互逻辑,也容易出现状态判断错误。
- 异常捕获逻辑不规范:
Selection.GetPropertyValue在选中内容格式混合时会返回DependencyProperty.UnsetValue,本身不会抛出异常,你当前的异常是强行给TextDecorationCollectionAdd空值触发的,用异常控制业务流程本身就属于不规范写法。 - 附加错误:
NewParagraphWhenSelectionIsEmpty方法中,FontWeight的判断错误用了btnItalics.IsChecked,应该改为btnBold.IsChecked,会导致空选时加粗和斜体状态串扰。
修复方案
不用自己逐字符遍历,直接通过属性值判断即可实现需求,修复后的下划线按钮点击逻辑如下:
private void btnUnderline_Click(object sender, RoutedEventArgs e) { bool isButtonChecked = (sender as ToggleButton).IsChecked ?? false; if (contentRichTextBox.Selection.IsEmpty) { NewParagraphWhenSelectionIsEmpty(); return; } var selection = contentRichTextBox.Selection; object decorationValue = selection.GetPropertyValue(Inline.TextDecorationsProperty); TextDecorationCollection newDecorations; // 格式混合状态,直接按按钮状态设置 if (decorationValue == DependencyProperty.UnsetValue) { newDecorations = new TextDecorationCollection(); if (isButtonChecked) { newDecorations.Add(TextDecorations.Underline); } } else { // 格式统一状态,切换下划线属性 var existingDecorations = decorationValue as TextDecorationCollection ?? new TextDecorationCollection(); newDecorations = new TextDecorationCollection(existingDecorations); if (isButtonChecked) { if (!newDecorations.Contains(TextDecorations.Underline[0])) newDecorations.Add(TextDecorations.Underline); } else { newDecorations.TryRemove(TextDecorations.Underline, out newDecorations); } } selection.ApplyPropertyValue(Inline.TextDecorationsProperty, newDecorations); }
删除线按钮逻辑和上面完全一致,只需要把所有Underline替换为Strikethrough即可。
另外修复NewParagraphWhenSelectionIsEmpty中的错误:
把
var fontWeight = (btnItalics.IsChecked ?? false) ? FontWeights.Bold : FontWeights.Normal;
改为
var fontWeight = (btnBold.IsChecked ?? false) ? FontWeights.Bold : FontWeights.Normal;
修复后即可解决格式偏移问题,同时逻辑更简洁,性能也优于逐字符遍历的实现。
内容的提问来源于stack exchange,提问作者Eldy Sparrownest
相关产品推荐
相关产品推荐

