How do you remove the space taken by an empty paragraph?

1.8k views Asked by At

How to get rid of space from a paragraph? I have tried using negative margin/padding but it doesn't accept negative values for these properties. Any idea?

My code is mentioned below:

<FlowDocument>
    <Section>
        <Paragraph>1</Paragraph>
        <Paragraph>2</Paragraph>
        <Paragraph></Paragraph>
        <Paragraph>4</Paragraph>
    </Section>
</FlowDocument>

And, outputs for the above code is given below:

enter image description here

EDIT: Here is an example that would make a bit more sense(as per the comments):

<FlowDocument>
    <Section>
        <Paragraph>
            <TextBlock Text="1" Visibility="Visible"/>
        </Paragraph>
        <Paragraph>
            <TextBlock Text="2" Visibility="Visible"/>
        </Paragraph>
        <Paragraph>
            <TextBlock Text="3" Visibility="Collapsed"/>
        </Paragraph>
        <Paragraph>
            <TextBlock Text="4" Visibility="Visible"/>
        </Paragraph>
    </Section>
</FlowDocument>

Which makes the exact same result.

4

There are 4 answers

6
GazTheDestroyer On BEST ANSWER

I hesitate to post this, as I'm sure there must be a better way, but since no-one else has replied....

A flow document Section appears to wrap paragraphs with whitespace equivilent to the paragraph's LineHeight.

LineHeight cannot be 0, but it can be very small. Setting LineHeight on the Section will remove whitespace around ALL paragraphs.

<FlowDocumentScrollViewer>
    <FlowDocumentScrollViewer.Resources>
        <Style TargetType="Paragraph">
            <Setter Property="Background" Value="LightBlue" />
        </Style>
    </FlowDocumentScrollViewer.Resources>

    <FlowDocument>
        <Section LineHeight="0.1">
            <Paragraph>1</Paragraph>
            <Paragraph>2</Paragraph>
            <Paragraph/>                       
            <Paragraph>4</Paragraph>
            <Paragraph>5</Paragraph>
        </Section>
    </FlowDocument>

</FlowDocumentScrollViewer>

Setting LineHeight like this will generally not affect the text inside the paragraphs, because the default LineStackingStrategy uses the height of the font instead. Note how the blank Paragraph still has height.

You might think setting LineHeight only on the blank paragraph would work, but Section will still honour the whitespace of the preceeding paragraph. Since the preceding paragraph has normal LineHeight, you still get the margin.

So, in order to remove your blank paragraph completely, you need to set LineHeight on the blank AND the preceeding paragraph, and tell your blank paragraph to use the LineHeight as its block height:

<FlowDocumentScrollViewer>
    <FlowDocumentScrollViewer.Resources>
        <Style TargetType="Paragraph">
            <Setter Property="Background" Value="LightBlue" />
        </Style>
    </FlowDocumentScrollViewer.Resources>

    <FlowDocument>
        <Section>
            <Paragraph>1</Paragraph>
            <Paragraph LineHeight="0.1">2</Paragraph>
            <Paragraph LineHeight="0.1" LineStackingStrategy="BlockLineHeight"/>                       
            <Paragraph>4</Paragraph>
            <Paragraph>5</Paragraph>
        </Section>
    </FlowDocument>

</FlowDocumentScrollViewer>

I tried to write a trigger that would do this automatically for blank paragraphs, but unfortunately Paragraph.Inlines.Count is not a DependencyProperty, and trying to use it to detect blank paragraphs is unreliable depending on when the paragraph gets populated.

2
Andrew Stephens On

If it's feasible in your scenario to have VM properties indicating whether the paragraphs are empty, then this would work:-

<FlowDocument>
  <FlowDocument.Resources>
    <Style TargetType="{x:Type Paragraph}">
      <Setter Property="Margin" Value="0,0,0,18"/>
      <Style.Triggers>
        <Trigger Property="Tag" Value="True">
           <Setter Property="Margin" Value="0"/>
           <Setter Property="LineHeight" Value="0.1"/>
           <Setter Property="LineStackingStrategy" Value="BlockLineHeight"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </FlowDocument.Resources>
  <Section>
     <Paragraph x:Name="p1" Tag="{Binding IsPara1Empty}">1</Paragraph>
     <Paragraph x:Name="p2" Tag="{Binding IsPara2Empty}">2</Paragraph>
     <Paragraph x:Name="p3" Tag="{Binding IsPara3Empty}"></Paragraph>
     <Paragraph x:Name="p4" Tag="{Binding IsPara4Empty}">4</Paragraph>
  </Section>
</FlowDocument>

Depending on your font size you might need to play with the style's "default" Margin value of "0,0,0,18".

Alternatively, if it's possible to programmatically determine if a paragraph is empty, you could create an inherited Paragraph control that exposes an IsEmpty dependency property. The trigger would use this instead of the Tag, and you wouldn't need the VM properties.

1
Joby James On

try this

<FlowDocument>

            <Section>

                <Paragraph>
                   1
                </Paragraph>
                <Paragraph>
                    2
                </Paragraph>
                <Paragraph local:AttachNew.MyProperty="1">

                </Paragraph>

                    <Paragraph>
                    4
                </Paragraph>
            </Section>
        </FlowDocument>

public class AttachNew
    {
        public static int GetMyProperty(DependencyObject obj)
        {
            return (int)obj.GetValue(MyPropertyProperty);
        }

        public static void SetMyProperty(DependencyObject obj, int value)
        {
            obj.SetValue(MyPropertyProperty, value);
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.RegisterAttached("MyProperty", typeof(int), typeof(AttachNew), new PropertyMetadata(0, new PropertyChangedCallback(ChangeProp)));

        private static void ChangeProp(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Section objparent = (d as System.Windows.Documents.Paragraph).Parent as Section;
            objparent.Blocks.Remove((d as System.Windows.Documents.Paragraph));
        }
    }
1
ph33nyx On

In HTML, the reason a paragraph tag, even when empty, takes up space is because it is a block-level element, and therefore it hasLayout. This means it has properties like padding and line-height assigned to it by the rendering agent, and also that it will cause a line break.

Can you find a way to detect if a paragraph will be empty and change its display rule? Visibility does not remove an element, only makes it invisible, so the paragraph tag will still cause that pesky line break. In fact, that line-height solution posted earlier still leaves in the line break. (An article about display vs visibility.)

The CSS rule display:none; can be used to remove it from the page flow (see hasLayout link above). I like to use a CSS class and apply that programatically. Something like this generally does the trick:

.hidden {display:none;height:0;width:0;}

You can also include line-height:0; into that class to cover the previous suggestion.