簡體   English   中英

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

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

如何制作沒有邊距、邊框、填充等的RichTextBox 換句話說,以與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"時,它會在 VisualStudio 設計器中顯示我想要的布局-直到我運行 demo 在演示中又錯了……當我關閉演示時,設計器又錯了。 這是 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

按照 Daniel Rose 在他的 las 編輯中建議的那樣添加雙向綁定后,它就可以工作了。 我仍然認為它不是很清楚(具有依賴屬性,因為我需要將PagePadding保持在 0 值)。 我認為這是一個 hack - bug 解決方法。 如果有人有更好的解決方案,請分享。

顯然,將FlowDocumentPagePadding更改為0,5是一個錯誤。 如果有人有 MSDN 帳戶,如果他們報告此錯誤會很好。

我知道這很煩人。

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

錯誤報告

這是關於 Microsoft Connect 的錯誤報告

我之前寫的整個事情都不起作用。 由於某種原因,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;
    }
}

嘗試這個。 它對我有用......它比這里的替代品要少得多......

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

其實這不是bug。 此行為旨在改進顯示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中插入符號具有更多的視覺效果,因此為它保留了更多的空間。

對我有用的解決方案只是設置<RichTextBox Padding="-5,0,0,0"> ,就像史蒂夫在帖子中提出的那樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM