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:
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.
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 ?
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.
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.
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.
<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);
}
}
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);
here is the bug report on Microsoft Connect
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With