【问题标题】:WPF: How to make RichTextBox look like TextBlock?WPF:如何使 RichTextBox 看起来像 TextBlock?
【发布时间】:2011-08-14 19:15:56
【问题描述】:

我怎样才能使RichTextBox 没有边距、边框、填充等?换句话说,以与TextBlock 相同的方式显示内容吗?我试过这个:

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

但是产生的结果还是不是我想要的:

在文档内容之前仍有一些空间(也可能在文档顶部或底部之后......)。如何删除它?


如果您对我为什么需要这个感兴趣:我试图让H.B.'s answer 对我的问题Create guitar chords editor in WPFkerning 一起使用,并且我不想在字符之间有不自然的空间。


编辑

所以它不是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>

我认为这将是一个容易回答的问题... 有趣的观察:当我设置了模板并在FlowDocument 上设置了PagePadding="0" 它显示了我想要的布局 在 VisualStudio 设计器中 - 直到我运行演示。在演示中又错了……当我关闭演示时,设计器又错了。这是 VS 的一个小错误,还是它实际上设置为正确的布局一段时间,但随后将 PagePadding 的值更改回某个错误值?


编辑#2

Daniel Rose 的编辑答案也不适合我。这是 XAML:

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

这是在代码中:

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); }
}

结果没有变化。剩余空间。


编辑#3

按照 Daniel Rose 在他的 las 编辑中建议的那样添加双向绑定后,它就可以工作了。我仍然认为它不是很清楚(具有依赖属性,因为我需要将PagePadding 保持在 0 值)。 我认为这是一个 hack - bug 解决方法。如果有人有更好的解决方案,请分享。

显然,将FlowDocumentPagePadding 更改为0,5 是一个错误。如果有人有 MSDN 帐户,如果他们报告此错误会很好。

【问题讨论】:

    标签: c# .net wpf richtextbox padding


    【解决方案1】:

    实际上这不是一个错误。此行为旨在改善显示 BiDi斜体 插入符号。

    查看 .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;
    }
    

    还有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;
    

    为了更有效,让我们看看以下三个控件,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>
    

    这些控件在使用相同的字体大小/样式时,内边距和边距显示如下:

    很容易看到TextBox 还具有一些额外的间距,旨在显示插入符号指示符。但是因为RichTextBox中的插入符号具有更多的视觉效果,所以为它保留了更多的空间。

    对我有用的解决方案只需设置&lt;RichTextBox Padding="-5,0,0,0"&gt;,就像Steve 在帖子中提出的那样。

    【讨论】:

      【解决方案2】:

      试试这个。它对我有用....它比这里的替代品要少得多...

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

      【讨论】:

        【解决方案3】:

        我知道这很烦人。

        RichTextBox 将此PagePadding 设置为CreateRenderScope(),即当它附加到可视树时。此时通常所有属性都已设置,因此 PagePadding 会被重置。

        我将要向您展示的是一种更通用的形式,说明如何使用附加属性执行此操作。在我自己的代码中,我通常会更严格地执行此操作,因为我知道 a)流文档不会改变(不必担心注册相同的处理程序两次)和 b)填充不会改变(事件处理程序只是 ((FlowDocument)s).PagePadding = new Thickness(0.0); . 为此,尽管我将提供一个通用的解决方案,您可以直接插入。

        解决方案:

                <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);
            }
        }
        

        原始源代码注释:

        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);
        

        错误报告

        here is the bug report on Microsoft Connect

        【讨论】:

        • @Markus Hütter:还有 2 条注释:首先,我猜这是一种错误,对吧?如果您有 MSDN 帐户(我没有),您是否考虑向 Microsoft 发送错误报告?也许他们会在 .NET 5 中修复它。其次,我倾向于不立即接受即使是好的答案。没有多少人阅读已接受的问题。我想让你有机会获得更多的支持,其他人可以提供一些额外的信息,甚至提供他们的解决方案。
        • @drasto 谢谢你的好心cmets。我也没有 MSDN 帐户。是的,从外面看,这似乎是一个错误,但由于他们明确地将这个语句包含在 CreateRenderScope 中,我不得不认为这种行为是有意的。但是,是的,我也认为有人应该将此报告为错误。
        • @Markus Hütter:我很快就会评论你对我的另一个问题的回答,但是那个需要更长的评论,不幸的是我现在很忙——吉他编辑器中的工作必须是推迟到我完成更紧急的工作人员。非常抱歉,再次感谢您的回答。
        • @drasto 我对代码进行了一些改进,并在我的答案中添加了更多信息。此外,此错误已被报告,因此我添加了指向此问题的链接作为错误报告的解决方法。
        • “Microsoft Connect 已停用”,我们的错误似乎已经消失了?
        【解决方案4】:

        我之前写的整个事情都行不通。由于某种原因,PagePadding 被覆盖为“5,0”。但是,当我使用数据绑定时,它可以正常工作。因此,只需将数据绑定到厚度为 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>
        

        后面的代码:

        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;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-22
          • 1970-01-01
          • 2011-07-30
          • 2011-07-04
          • 1970-01-01
          • 2012-08-24
          • 1970-01-01
          • 2011-11-15
          相关资源
          最近更新 更多