【发布时间】:2016-10-19 20:57:53
【问题描述】:
我有一个 C# WPF RichTextBox,它允许通过 Slider 调整 ScaleX 和 ScaleY LayoutTransform。不幸的是,这种缩放会导致插入符号停止渲染,这是一个可以根据代码 at this SO post here 修复的错误。更不幸的是,设置插入符号的RenderTransform 会导致拼写检查红色波浪线在您键入时停止显示。似乎取消RichTextBox 的焦点并通过单击Slider 再次聚焦将导致所有红色波浪线重新出现。 您可以在我的 GitHub here 上查看此错误的演示。
问题:如何在用户键入时显示红色波浪形拼写检查行,同时仍允许 RichTextBox 缩放和完全渲染的所有比例级别的插入符号? 我试过手动调用GetSpellingError(TextPointer),这很有效……有点。除非我在RichTextBox 的每个 单词上调用GetSpellingError,否则它并不完全可靠,当有大量内容时,计算速度非常慢。我还尝试对Speller 和相关内部类中的项目使用反射等,例如Highlights、SpellerStatusTable 和SpellerHighlightLayer。在查看SpellerStatusTable 的运行列表(其中似乎包含有关运行是干净还是脏的信息)时,在单击滑块之前不会更新运行以包含错误,这意味着RichTextBox 不会重新检查拼写错误。
在CustomRichTextBox.cs 中注释掉caretSubElement.RenderTransform = scaleTransform; “修复”了问题,但随后又中断了插入符号渲染。
代码--
MainWindow.xaml:
<Window x:Class="BrokenRichTextBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BrokenRichTextBox"
mc:Ignorable="d"
Title="Rich Text Box Testing" Height="350" Width="525">
<Grid Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Slider Name="FontZoomSlider" Grid.Row="0" Width="150" Value="2" Minimum="0.3" Maximum="10" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<local:CustomRichTextBox x:Name="richTextBox"
Grid.Row="1"
SpellCheck.IsEnabled="True"
ScaleX="{Binding ElementName=FontZoomSlider, Path=Value}"
ScaleY="{Binding ElementName=FontZoomSlider, Path=Value}"
AcceptsTab="True">
<local:CustomRichTextBox.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=richTextBox, Path=ScaleX, Mode=TwoWay}"
ScaleY="{Binding ElementName=richTextBox, Path=ScaleY, Mode=TwoWay}"/>
</local:CustomRichTextBox.LayoutTransform>
<FlowDocument>
<Paragraph>
<Run>I am some sample text withhh typooos</Run>
</Paragraph>
<Paragraph>
<Run FontStyle="Italic">I am some more sample text in italic</Run>
</Paragraph>
</FlowDocument>
</local:CustomRichTextBox>
</Grid>
</Window>
CustomRichTextBox.cs:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace BrokenRichTextBox
{
class CustomRichTextBox : RichTextBox
{
private bool _didAddLayoutUpdatedEvent = false;
public CustomRichTextBox() : base()
{
UpdateAdorner();
if (!_didAddLayoutUpdatedEvent)
{
_didAddLayoutUpdatedEvent = true;
LayoutUpdated += updateAdorner;
}
}
public void UpdateAdorner()
{
updateAdorner(null, null);
}
// Fixing missing caret bug code adjusted from: https://stackoverflow.com/questions/5180585/viewbox-makes-richtextbox-lose-its-caret
private void updateAdorner(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
Selection.GetType().GetMethod("System.Windows.Documents.ITextSelection.UpdateCaretAndHighlight", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(
Selection, null);
var caretElement = Selection.GetType().GetProperty("CaretElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Selection, null);
if (caretElement == null)
return;
var caretSubElement = caretElement.GetType().GetField("_caretElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(caretElement) as UIElement;
if (caretSubElement == null) return;
// Scale slightly differently if in italic just so it looks a little bit nicer
bool isItalic = (bool)caretElement.GetType().GetField("_italic", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(caretElement);
double scaleX = 1;
if (!isItalic)
scaleX = (1 / ScaleX);
else
scaleX = 0.685;// output;
double scaleY = 1;
var scaleTransform = new ScaleTransform(scaleX, scaleY);
caretSubElement.RenderTransform = scaleTransform; // The line of trouble
}), DispatcherPriority.ContextIdle);
}
public double ScaleX
{
get { return (double)GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}
public static readonly DependencyProperty ScaleXProperty =
DependencyProperty.Register("ScaleX", typeof(double), typeof(CustomRichTextBox), new UIPropertyMetadata(1.0));
public double ScaleY
{
get { return (double)GetValue(ScaleYProperty); }
set { SetValue(ScaleYProperty, value); }
}
public static readonly DependencyProperty ScaleYProperty =
DependencyProperty.Register("ScaleY", typeof(double), typeof(CustomRichTextBox), new UIPropertyMetadata(1.0));
}
}
【问题讨论】:
-
希望Jon Skeet 看到这个。
-
这是一个非常典型的 WPF 错误。拼写检查和重新渲染被延迟,当你喜欢它发生时很容易不触发它。每个 .NET 版本都有很多 WPF 错误修复,但仅当您在项目中定位该版本时才会打开它们。所以首先确保你的目标是 4.6.2。如果您仍然看到它,那么让他们在 4.6.3 上工作,这只有在您通过 connect.microsoft.com 告诉他们时才有效
-
@HansPassant 感谢您的建议。我确实尝试了对 4.6.2 的更新,但遗憾的是该错误仍然存在。我想在某个地方有一些手动重新渲染调用或“请重新检查我的文本”调用,但我还没有找到一个可行的方法。一位朋友建议我尝试更多地使用手动
GetSpellingError调用,所以我会仔细研究一下。
标签: c# wpf richtextbox spell-checking