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

时间:2011-04-28 14:53:12

标签: c# .net wpf richtextbox padding

如何在没有边距,边框,填充等的情况下制作RichTextBox?换句话说,以与TextBlock相同的方式显示内容呢?我试过这个:

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

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

enter image description here

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


如果您有兴趣我为什么需要这个:我尝试H.B.'s answer来问我的问题Create guitar chords editor in WPF以便与kerning合作,我不希望角色之间有不自然的空间。


修改

所以至少不仅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>

我觉得这很容易回答...... 有趣的观察:当我有模板集并在PagePadding="0" 上设置FlowDocument时,它会显示我想要的布局在VisualStudio设计器中 - 直到我运行演示。在演示中再次出错......当我关闭演示时,设计师再次出错了。这是VS的一个小错误,或者它实际上设置为正确的布局一段时间但是然后某些内容会将PagePadding的值更改回某个错误的值?


编辑#2

丹尼尔罗斯的编辑答案也不适用于我。这是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

添加双向绑定后,丹尼尔罗斯在他的拉斯编辑中提出它可行。我仍然不认为它非常清楚(具有依赖属性,因为我需要将PagePadding保持为0值)。 我认为这是一个黑客攻击方法。如果有人有更好的解决方案请分享。

显然,将PagePadding更改为FlowDocument0,5是一个错误。如果有人拥有MSDN帐户,那么如果他们报告了这个错误就会很好。

4 个答案:

答案 0 :(得分:21)

我知道这很烦人。

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

我要向您展示的是如何使用附加财产执行此操作的更一般形式。在我自己的代码中,我通常更紧密地执行此操作,因为我知道a)flowdocument不会更改(不必担心两次注册相同的处理程序)和b)填充不会更改(事件处理程序只是{{1虽然我会提供一个你可以插入的通用解决方案。

解决方案:

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

错误报告

here is the bug report on Microsoft Connect

答案 1 :(得分:3)

我之前写的全部内容都不起作用。出于某种原因,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;
    }
}

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

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

enter image description here

很容易看到 TextBox 也有一些额外的间距,用于显示插入符号指示符。但是由于在 RichTextBox 中插入符号具有更多的视觉效果,因此为其保留了更多空间。

对我有用的解决方案只是设置 <RichTextBox Padding="-5,0,0,0">,就像 Steve 在帖子中提出的一样。