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

发布于 2024-11-04 02:04:43 字数 3059 浏览 0 评论 0原文

如何制作 RichTextBox< /a> 没有边距、边框、填充等?换句话说,以与 TextBlock 是吗?我已经尝试过:

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

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

在此处输入图像描述

之前还有一些空格文档内容(也可能在文档之后、顶部或底部......)。我怎样才能删除它?


如果您感兴趣为什么我需要这个:我试图制作 HB 对我的问题的回答在 WPF 中创建吉他和弦编辑器以使用 字距调整,我不想在字符之间有不自然的空格。


编辑

所以它不是 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" 它会显示我想要的布局 直到我运行演示。在演示中它又出错了......当我关闭演示时,设计器中又出错了。这是 VS 的一个小错误,还是它实际上设置为正确的布局一段时间,但随后某些东西将 PagePadding 的值更改回某个错误的值?


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

结果没有更改。空间依然存在。


Edit#3

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

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

How can I make RichTextBox with no Margin, Border, Padding etc. ? In another words to display content in the same way as TextBlock does it ? 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:

enter image description here

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 H.B.'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.


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

<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. 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 ?


Edit#2

Daniel Rose's edited answer is also not working for me. This is 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

After adding Two-Way binding as Daniel Rose suggested in his las edit it works. Still I don't really think it is very clear (to have dependency property because I need to keep PagePadding at 0 value). I think it is a hack - bug workaround. If somebody has better solution please share it.

Obviously "changing PagePadding" of FlowDocument to 0,5 is a bug. If somebody has MSDN account it would be nice if they reported this bug.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

时光沙漏 2024-11-11 02:04:43

我知道这很烦人。

RichTextBox 在其 CreateRenderScope() 中设置此 PagePadding,即当它附加到可视化树时。此时,所有属性通常都已经设置,因此 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);

错误报告

这是 Microsoft Connect 上的错误报告

I know this is annoying as hell.

RichTextBox sets this PagePadding in it's CreateRenderScope(), ie when it gets attached to the visual tree. At this time all properties are usually already set and thus the PagePadding gets reset.

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.

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:

// 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

画尸师 2024-11-11 02:04:43

我之前写的整个事情都不起作用。由于某种原因,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;
    }
}

The whole thing as I previously wrote doesn't work. For some reason the PagePadding is being overwritten as "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:

<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;
    }
}
極樂鬼 2024-11-11 02:04:43

试试这个。它对我有用......它比这里的替代方案要少很多头痛......

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

Try this. It works for me.... It's a lot less headache than the alternatives here...

<RichTextBox Padding="-5,0,-5,0">
   <FlowDocument />
</RichTextBox>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文