RichTextBox放置在ViewBox内并缩放到10 - 1000%的各个级别。当百分比小于100%时,插入符号在随机光标位置消失。
据我所知,当视觉缩小(压缩)时,它会丢失像素。有什么方法可以让我不再失去光标吗?
<Viewbox>
<RichTextBox Name="richTextBox1" Width="400" Height="400" />
</Viewbox>
答案 0 :(得分:7)
最终编辑:
嘿那里,只是想说,你甚至可以在没有反思的情况下工作!这不是优化的代码,我会留给你自己。这仍然依赖于内部的东西。所以它来了:代码隐藏:
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的内容缩放而不是ViewBox中的RichTextBox。如果这是一个选项,你还没有回答。
现在其他一切都会变得复杂,或多或少有问题:
您可以使用Moq或类似的东西(想想Moles左右......)来替换SystemParameters.CaretWidth的getter以适应ViewBox所施加的ScaleTransform。这有几个问题!第一:这些库设计用于测试场景,不建议用于生产。第二:您必须在RichTextBox实例化Caret之前设置该值。但这很难,因为您事先并不知道ViewBox如何缩放RichTextBox。所以,这不是一个好的选择!
第二个(坏)选项是使用Reflection来获得这个漂亮的小班System.Windows.Documents.CaretElement
。你可以通过RichTextBox.TextEditor.Selection.CaretElement
到达那里(你必须使用Reflection,因为这些属性和类大部分是internal sealed
)。由于这是一个Adorner,您可以在那里附加一个可以反转Scaling的ScaleTransform。我不得不说:这是既未测试也未推荐!
你的选择在这里是有限的,如果我是你,我会先去猜测!
修改强>:
如果您确实希望了解第二条(不良)路线,那么如果您将ScaleTransform应用于那些可以通过类型为{{1}的私人字段_caretElement
的单个子项,那么您可能会有更多的运气}。如果我正确阅读该代码,那么该子元素就是您的实际Caret Visual。主要元素似乎用于绘制选择几何。如果你真的想这样做,那么在那里应用ScaleTransform。
修改强>:
完整的示例:
XAML:
CaretSubElement
代码隐藏:
<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>
这对我有用。一切都说了。
答案 1 :(得分:1)
AFAIK你无法真正解决这个问题。 ViewBox正在使用ScaleTransform,缩小时,ScaleTransform将隐藏某些行,因为它无法显示所有内容。 ScaleTransform没有使用非常先进的算法来进行扩展(它只是以最快的方式完成)并且我认为你不能改变它......