7

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.

  • 1
    Is there a reason you are hard coding 4 paragraphs when going by your question they could be blank? A user would not be able to add anything to the paragraph if it was squashed anyway so should it even be there? If the paragraphs are displaying read only information from somewhere else perhaps its better to add the paragraphs as needed? – kenjara Jun 19 '15 at 14:23
  • 2
    Indeed I was thinking the same thing. Why not filter empty paragraphs at view model level? – Maverik Jun 19 '15 at 14:38
  • My question is a simplified version of my issue. The paragraph does not exactly contain nothing, they have multiple containers. But I can handle that part of the issue, all I need is to know how to completely hide a paragraph as it does not have any "Visibility" property. – Maxime Tremblay-Savard Jun 19 '15 at 15:25
  • 1
    You can hide paragraph by removing it from its parent. However, you can still keep it in memory – Liero Jun 25 '15 at 10:39

4 Answers4

5

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.

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103
  • I was following this exact strategy and running into Inlines.Count=0 triggering for all Paragraphs. +1 :) – Maverik Jun 19 '15 at 14:19
  • Looks a bit hackish but works fine! About the Paragraph.Inlines.Count, I don't need to do that because I already know what's in my paragraphs. Most of the time(in my case), the paragraph only contain one TextBlock and I know what is the text in it, but hiding the textblock still leaves a blank space because of the Paragraph. Which explains why I needed to know how to get rid of this space. – Maxime Tremblay-Savard Jun 19 '15 at 15:30
  • It is indeed hackish which is why I was hesitant to post. Glad it seems to work at least. – GazTheDestroyer Jun 19 '15 at 15:33
  • I'll leave some time for others to give an answer and if no one has a good answer i'll give you the "correct answer" and bounty. Thanks for your input on my issue! – Maxime Tremblay-Savard Jun 19 '15 at 15:38
  • No problem. I'm interested myself to see if there is a "proper" solution. – GazTheDestroyer Jun 19 '15 at 15:39
  • Considering that `FlowDocument` is not really a layout component, I'd say that the only "proper" solution would be removing the whole Paragraph from the document. If that's not a choice, then this is as good a solution as any. – almulo Jun 22 '15 at 08:03
2

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.

Andrew Stephens
  • 9,413
  • 6
  • 76
  • 152
1

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));
        }
    }
Joby James
  • 429
  • 8
  • 22
1

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.

ph33nyx
  • 301
  • 2
  • 5