gpt4 book ai didi

wpf - ViewBox 使 RichTextBox 失去插入符

转载 作者:行者123 更新时间:2023-12-02 08:31:33 29 4
gpt4 key购买 nike

RichTextBox 放置在 ViewBox 内并缩放至 10 - 1000% 的各个级别。当百分比小于 100% 时,插入符号会在随机光标位置消失。

我知道当视觉效果被缩小(压缩)时,它会丢失像素。有什么办法可以让我不再丢失光标吗?

    <Viewbox>
<RichTextBox Name="richTextBox1" Width="400" Height="400" />
</Viewbox>

最佳答案

最终编辑:

嘿,我只是想说,你甚至可以在没有反射(reflection)的情况下让这个工作起来!这不是优化的代码,我将其留给您自己。而且这还是要靠内部的东西。所以它来了:

隐藏代码:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
rtb.LayoutUpdated += (sender, args) =>
{
var child = VisualTreeHelper.GetChild(vb, 0) as ContainerVisual;
var scale = child.Transform as ScaleTransform;
rtb.ScaleX = scale.ScaleX;
};
}
}

public class RTBwithVisibleCaret:RichTextBox
{
private UIElement _flowDocumentView;
private AdornerLayer _adornerLayer;
private UIElement _caretSubElement;
private ScaleTransform _scaleTransform;

public RTBwithVisibleCaret()
{
LayoutUpdated += (sender, args) =>
{
if (!IsKeyboardFocused) return;
if(_adornerLayer == null)
_adornerLayer = AdornerLayer.GetAdornerLayer(_flowDocumentView);
if (_adornerLayer == null || _flowDocumentView == null) return;
if(_scaleTransform != null && _caretSubElement!= null)
{
_scaleTransform.ScaleX = 1/ScaleX;
_adornerLayer.Update(_flowDocumentView);
}
else
{
var adorners = _adornerLayer.GetAdorners(_flowDocumentView);
if(adorners == null || adorners.Length<1) return;
var caret = adorners[0];
_caretSubElement = (UIElement) VisualTreeHelper.GetChild(caret, 0);
if(!(_caretSubElement.RenderTransform is ScaleTransform))
{
_scaleTransform = new ScaleTransform(1 / ScaleX, 1);
_caretSubElement.RenderTransform = _scaleTransform;
}
}
};
}

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var cthost = GetTemplateChild("PART_ContentHost") as FrameworkElement;
_flowDocumentView = cthost is ScrollViewer ? (UIElement)((ScrollViewer)cthost).Content : ((Decorator)cthost).Child;
}

public double ScaleX
{
get { return (double)GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}
public static readonly DependencyProperty ScaleXProperty =
DependencyProperty.Register("ScaleX", typeof(double), typeof(RTBwithVisibleCaret), new UIPropertyMetadata(1.0));
}

使用此 XAML:

<Window x:Class="RTBinViewBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:RTBinViewBoxTest="clr-namespace:RTBinViewBoxTest" Title="MainWindow" Height="350" Width="525">
<Viewbox Height="100" x:Name="vb">
<RTBinViewBoxTest:RTBwithVisibleCaret Width="70" x:Name="rtb">
<FlowDocument>
<Paragraph>
<Run>long long long long long long long long long long long long long long long long long long long long long long long long text</Run>
</Paragraph>
</FlowDocument>
</RTBinViewBoxTest:RTBwithVisibleCaret>
</Viewbox>
</Window>

是的,当我看到所有这些都可以通过视觉树访问时,我开始思考!您还可以遍历 VisualTree 来获取 FlowDocumentView,而不是从 RichTextBox 继承(获取 TemplateChild 需要它)!

原帖:

好的,让我们看看您的选择是什么:

正如我在上面的评论中所述:实现此目的的最简单方法是让 RichTextBox 的内容缩放,而不是将 RichTextBox 放在 ViewBox 内。您(尚未)回答这是否是一个选项。

现在其他一切都会变得复杂并且或多或少存在问题:

您可以使用Moq或类似的东西(想想摩尔斯之类的......)来代替 SystemParameters.CaretWidth 的 setter/getter 以适应 ViewBox 所施加的 ScaleTransform。这有几个问题!首先:这些库设计用于测试场景,不建议用于生产使用。其次:您必须在 RichTextBox 实例化插入符之前设置该值。但这会很困难,因为您事先不知道 ViewBox 如何缩放 RichTextBox。所以,这不是一个好的选择!

第二个(坏)选项是使用反射来访问这个漂亮的小类 System.Windows.Documents.CaretElement 。您可以通过RichTextBox.TextEditor.Selection.CaretElement到达那里(您必须使用反射,因为这些属性和类大部分都是 internal sealed )。由于这是一个装饰器,您可以在其中附加一个 ScaleTransform 来反转缩放。但我不得不说:这既没有经过测试,也没有推荐!

您的选择有限,如果我是您,我会进行第一个猜测!

编辑:

如果你真的想走第二条(坏)路线,如果你将 ScaleTransform 应用于可以通过私有(private)字段 _caretElement 获得的装饰器单个子元素,你可能会更幸运。类型 CaretSubElement 。如果我正确地阅读了该代码,那么该子元素就是您实际的 Caret Visual。主要元素似乎用于绘制选择几何图形。如果您确实想这样做,请在那里应用 ScaleTransform。

编辑:

要遵循的完整示例:

XAML:

<Window x:Class="RTBinViewBoxTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Viewbox Height="100" x:Name="vb">
<RichTextBox Width="70" Name="rtb">
<FlowDocument>
<Paragraph>
<Run>long long long long long long long long long long long long long long long long long long long long long long long long text</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Viewbox>
</Window>

隐藏代码:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
rtb.GotFocus +=RtbOnGotFocus;
}

private void RtbOnGotFocus(object s, RoutedEventArgs routedEventArgs)
{
rtb.LayoutUpdated += (sender, args) =>
{
var child = VisualTreeHelper.GetChild(vb, 0) as ContainerVisual;
var scale = child.Transform as ScaleTransform;
rtb.Selection.GetType().GetMethod("System.Windows.Documents.ITextSelection.UpdateCaretAndHighlight", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(
rtb.Selection, null);

var caretElement=rtb.Selection.GetType().GetProperty("CaretElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(rtb.Selection, null);
if (caretElement == null)
return;
var caretSubElement = caretElement.GetType().GetField("_caretElement", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(caretElement) as UIElement;
if (caretSubElement == null) return;
var scaleTransform = new ScaleTransform(1/scale.ScaleX, 1);
caretSubElement.RenderTransform = scaleTransform;
};
}
}

这对我有用。一切都说了。

关于wpf - ViewBox 使 RichTextBox 失去插入符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5180585/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com