简体   繁体   English

WPF:如何使 RichTextBox 看起来像 TextBlock?

[英]WPF: How to make RichTextBox look like TextBlock?

How can I make RichTextBox with no Margin, Border, Padding etc. ?如何制作没有边距、边框、填充等的RichTextBox In another words to display content in the same way as TextBlock does it?换句话说,以与TextBlock相同的方式显示内容吗? I have tried this:我试过这个:

<RichTextBox Margin="0" Padding="0" Grid.Row="0" BorderThickness="0" >
    <FlowDocument >
        <Paragraph>LLL</Paragraph>
    </FlowDocument>
</RichTextBox>
<TextBlock>LLL</TextBlock>

But the result produces is still not what I want:但产生的结果仍然不是我想要的:

在此处输入图像描述

There is still some space before document content (and also maybe after, on the top or bottom of the document...).文档内容之前仍有一些空间(也可能在文档顶部或底部之后......)。 How can I remove it?我怎样才能删除它?


If you are interested why I need this: I trying to make HB's answer to my question Create guitar chords editor in WPF to work with kerning and I don't want to have unnatural space between characters.如果您对我为什么需要这个感兴趣:我试图让HB 回答我的问题在 WPF 中创建吉他和弦编辑器以使用字距调整,我不想在字符之间有不自然的空间。


Edit编辑

So it is not ControlTemplate at least not only that because following code will produce exactly the same result (as the one on the picture above):所以它不是ControlTemplate至少不仅因为以下代码将产生完全相同的结果(如上图所示):

<RichTextBox Margin="0" Padding="0" Grid.Row="0" BorderThickness="0">
    <RichTextBox.Template>
        <ControlTemplate>
            <ScrollViewer Padding="0" Margin="0" x:Name="PART_ContentHost"/>
        </ControlTemplate>
    </RichTextBox.Template>
    <FlowDocument PagePadding="0">
        <Paragraph Padding="0" Margin="0" >LLL</Paragraph>
    </FlowDocument>
</RichTextBox>

And I thought this will be question easy to answer... Interesting observation: when I have template set and I set PagePadding="0" on FlowDocument it displays layout that I want in the VisualStudio designer - until I run the demo .而且我认为这将是一个容易回答的问题......有趣的观察:当我设置模板并在FlowDocument上设置PagePadding="0"时,它会在 VisualStudio 设计器中显示我想要的布局-直到我运行 demo In the demo it is wrong again... And when I close the demo it is wrong again in the designer.在演示中又错了……当我关闭演示时,设计器又错了。 This is a small bug of VS or is it actually set to the right layout for a while but then something changes value of PagePadding back to some wrong value?这是 VS 的一个小错误,还是它实际上设置了一段时间的正确布局,但随后某些东西将PagePadding的值更改回了某个错误的值?


Edit#2编辑#2

Daniel Rose's edited answer is also not working for me.丹尼尔罗斯编辑的答案也不适合我。 This is XAML:这是 XAML:

<FlowDocument PagePadding="{Binding PagePadding}">
    <Paragraph x:Name="paragraph" Padding="0" 
        TextIndent="0"  Margin="0,0,0,0" >hello</Paragraph>
</FlowDocument>

And this is in code:这是在代码中:

public static DependencyProperty PagePaddingProperty =
            DependencyProperty.Register("PagePadding", typeof(Thickness),   typeof(EditableTextBlock),
            new PropertyMetadata(new Thickness(0)));

public Thickness PagePadding {
    get { return (Thickness)GetValue(PagePaddingProperty); }
    set { SetValue(PagePaddingProperty, value); }
}

No changes to the result .结果没有变化 Space remains.空间依然存在。


Edit#3编辑#3

After adding Two-Way binding as Daniel Rose suggested in his las edit it works.按照 Daniel Rose 在他的 las 编辑中建议的那样添加双向绑定后,它就可以工作了。 Still I don't really think it is very clear (to have dependency property because I need to keep PagePadding at 0 value).我仍然认为它不是很清楚(具有依赖属性,因为我需要将PagePadding保持在 0 值)。 I think it is a hack - bug workaround.我认为这是一个 hack - bug 解决方法。 If somebody has better solution please share it.如果有人有更好的解决方案,请分享。

Obviously "changing PagePadding " of FlowDocument to 0,5 is a bug.显然,将FlowDocumentPagePadding更改为0,5是一个错误。 If somebody has MSDN account it would be nice if they reported this bug.如果有人有 MSDN 帐户,如果他们报告此错误会很好。

I know this is annoying as hell.我知道这很烦人。

RichTextBox sets this PagePadding in it's CreateRenderScope() , ie when it gets attached to the visual tree. RichTextBox将此 PagePadding 设置在它的CreateRenderScope()中,即当它附加到可视树时。 At this time all properties are usually already set and thus the PagePadding gets reset.此时,所有属性通常都已设置,因此 PagePadding 会被重置。

What I'm about to show you is a more general form of how you can do this using an attached property.我将要向您展示的是一种更通用的形式,说明如何使用附加属性来做到这一点。 In my own code I do this usually more tightly because I know that a) the flowdocument does not change (not having to worry about registering the same handler twice) and b) the padding does not change (having the eventhandler just be ((FlowDocument)s).PagePadding = new Thickness(0.0); . For this being SO though I'll provide a general solution that you can just plug in.在我自己的代码中,我通常会更严格地执行此操作,因为我知道 a)流文档不会改变(不必担心注册相同的处理程序两次)和 b)填充不会改变(事件处理程序只是((FlowDocument)s).PagePadding = new Thickness(0.0); 。为此,尽管我将提供一个您可以插入的通用解决方案。

The Solution:解决方案:

        <RichTextBox BorderThickness="0" Margin="0" Padding="0">
            <FlowDocument local:FlowDocumentPagePadding.PagePadding="0">
                <Paragraph>
                    <Run>text</Run>
                </Paragraph>
            </FlowDocument>
        </RichTextBox>

public static class FlowDocumentPagePadding
{
    public static Thickness GetPagePadding(DependencyObject obj)
    {
        return (Thickness)obj.GetValue(PagePaddingProperty);
    }
    public static void SetPagePadding(DependencyObject obj, Thickness value)
    {
        obj.SetValue(PagePaddingProperty, value);
    }
    public static readonly DependencyProperty PagePaddingProperty =
        DependencyProperty.RegisterAttached("PagePadding", typeof(Thickness), typeof(FlowDocumentPagePadding), new UIPropertyMetadata(new Thickness(double.NegativeInfinity),(o, args) =>
            {
                var fd = o as FlowDocument;
                if (fd == null) return;
                var dpd = DependencyPropertyDescriptor.FromProperty(FlowDocument.PagePaddingProperty, typeof(FlowDocument));
                dpd.RemoveValueChanged(fd, PaddingChanged);
                fd.PagePadding = (Thickness) args.NewValue;
                dpd.AddValueChanged(fd, PaddingChanged);
            }));
    public static void PaddingChanged(object s, EventArgs e)
    {
        ((FlowDocument)s).PagePadding = GetPagePadding((DependencyObject)s);
    }
}

original sourcecode commentary:原始源代码注释:

In the original source of RichTextBox.CreateRenderScope() the developers included this comment:RichTextBox.CreateRenderScope()的原始源代码中,开发人员包含了以下注释:

// Set a margin so that the BiDi Or Italic caret has room to render at the edges of content.
// Otherwise, anti-aliasing or italic causes the caret to be partially clipped.
renderScope.Document.PagePadding = new Thickness(CaretElement.CaretPaddingWidth, 0, CaretElement.CaretPaddingWidth, 0);

bug report错误报告

here is the bug report on Microsoft Connect 这是关于 Microsoft Connect 的错误报告

The whole thing as I previously wrote doesn't work.我之前写的整个事情都不起作用。 For some reason the PagePadding is being overwritten as "5,0".由于某种原因,PagePadding 被覆盖为“5,0”。 However, when I used data-binding, it worked properly.但是,当我使用数据绑定时,它可以正常工作。 So simply databind to a Thickness of 0. For it to work, you have to two-way databind:所以只需将数据绑定到 0 的厚度。要使其工作,您必须进行双向数据绑定:

<Window
    x:Class="WpfApplication1.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">
    <StackPanel Orientation="Vertical">
        <RichTextBox BorderThickness="0" Margin="0" Padding="0" >
            <FlowDocument PagePadding="{Binding PagePadding, Mode=TwoWay}">
                <Paragraph>LLL</Paragraph>
            </FlowDocument>
        </RichTextBox>
        <TextBlock>LLL</TextBlock>
    </StackPanel>
</Window>

Code behind:后面的代码:

namespace WpfApplication1
{
    using System.ComponentModel;
    using System.Windows;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private Thickness pagePadding;

        public Thickness PagePadding
        {
            get
            {
                return this.pagePadding;
            }
            set
            {
                this.pagePadding = value;
                this.Changed("PagePadding");
            }
        }

        private void Changed(string name)
        {
            var handlers = this.PropertyChanged;
            if (handlers != null)
            {
                handlers.Invoke(this, new PropertyChangedEventArgs(name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Try this.尝试这个。 It works for me.... It's a lot less headache than the alternatives here...它对我有用......它比这里的替代品要少得多......

<RichTextBox Padding="-5,0,-5,0">
   <FlowDocument />
</RichTextBox>

Actually it's not a bug.其实这不是bug。 This behavior intended to improve display BiDi and Italic caret indicator.此行为旨在改进显示BiDi斜体插入符号指示器。

Look at.Net 4.8 source, in the RichTextBox.cs file:查看 .Net 4.8 源码,在RichTextBox.cs文件中:

// Allocates the initial render scope for this control.
internal override FrameworkElement CreateRenderScope()
{
    FlowDocumentView renderScope = new FlowDocumentView();
    renderScope.Document = this.Document;

    // Set a margin so that the BiDi Or Italic caret has room to render at the edges of content.
    // Otherwise, anti-aliasing or italic causes the caret to be partially clipped.
    renderScope.Document.PagePadding = new Thickness(CaretElement.CaretPaddingWidth, 0, CaretElement.CaretPaddingWidth, 0);

    // We want current style to ignore all properties from theme style for renderScope.
    renderScope.OverridesDefaultStyle = true;

    return renderScope;
}

And the CaretElement.CaretPaddingWidth definition in the CaretElement.cs file:以及CaretElement.cs文件中的CaretElement.CaretPaddingWidth定义:

// Caret padding width to ensure the visible caret for Bidi and Italic.
// Control(TextBox/RichTextBox) must have the enough padding to display
// BiDi and Italic caret indicator.
internal const double CaretPaddingWidth = 5.0;

For more validity let look at the following three controls, TextBlock , TextBox and RichTextBox :为了更有效,让我们看看以下三个控件, TextBlockTextBoxRichTextBox

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock FontStyle="Italic" FontSize="48">LLL in TextBlock</TextBlock>
    <TextBox Grid.Row="1" FontStyle="Italic" FontSize="48" BorderThickness="0">LLL in TextBox</TextBox>        
    <RichTextBox Grid.Row="2" FontStyle="Italic" FontSize="48"  BorderThickness="0" Height="Auto"  >
        <FlowDocument PagePadding="0" >
            <Paragraph TextIndent="0">LLL in RichTextBox</Paragraph>
        </FlowDocument>
    </RichTextBox>
</Grid>

These controls, when using the same font size/style, padding and margin are displaying like on screenshot below:这些控件在使用相同的字体大小/样式时,填充和边距显示如下:

在此处输入图像描述

As easy to see the TextBox also has some additional spacing that intended by displaying the caret indicator.很容易看到TextBox还具有一些额外的间距,旨在通过显示插入符号指示符。 But because of in the RichTextBox the caret indicator has more visual effects, more space is reserved for it.但是由于在RichTextBox中插入符号具有更多的视觉效果,因此为它保留了更多的空间。

The solution that worked for me is simply set <RichTextBox Padding="-5,0,0,0"> , like proposed in post by Steve .对我有用的解决方案只是设置<RichTextBox Padding="-5,0,0,0"> ,就像史蒂夫在帖子中提出的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM