如何删除空段落占用的空间?

7
如何删除段落中的空格?我尝试使用负的margin/padding,但是这些属性不接受负值。有什么想法吗?
以下是我的代码:
<FlowDocument>
    <Section>
        <Paragraph>1</Paragraph>
        <Paragraph>2</Paragraph>
        <Paragraph></Paragraph>
        <Paragraph>4</Paragraph>
    </Section>
</FlowDocument>

以下是上述代码的输出结果:

enter image description here

编辑:以下是一个更为合理的示例(根据评论):
<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>

这会产生完全相同的结果。

1
你硬编码4个段落是有原因的吗?根据你的问题,这些段落可能是空白的。如果段落被压缩了,用户将无法添加任何内容,那么它是否应该存在呢?如果这些段落显示来自其他地方的只读信息,也许最好根据需要添加段落? - kenjara
2
确实,我也在想同样的事情。为什么不在视图模型级别过滤空段落呢? - Maverik
我的问题是我问题的简化版本。这段文字不完全没有内容,它们有多个容器。但我可以处理问题的这一部分,我需要知道如何完全隐藏一个段落,因为它没有任何“可见性”属性。 - Maxime Tremblay-Savard
1
您可以通过将段落从其父级中删除来隐藏它。但是,您仍然可以将其保留在内存中。 - Liero
4个回答

5

我犹豫是否要发布这篇文章,因为我相信一定有更好的方法,但既然没有人回复……

流程文档中的Section似乎会用与段落LineHeight相当的空白包装。

LineHeight不能为0,但可以非常小。在Section上设置LineHeight将删除所有段落周围的空白。

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

设置LineHeight通常不会影响段落内的文本,因为默认的LineStackingStrategy使用字体的高度。请注意空白段落仍然具有高度。

你可能认为只在空白段落上设置LineHeight就可以解决问题,但是Section仍然会尊重前一个段落的空格。由于前一个段落具有正常的LineHeight,所以你仍然会得到边距。

因此,为了完全删除空白段落,你需要在空白段落和前一个段落上设置LineHeight,并告诉你的空白段落使用LineHeight作为其块高度:

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

我尝试编写一个触发器来自动完成空白段落的操作,但不幸的是,Paragraph.Inlines.Count不是依赖属性,并且尝试使用它来检测空白段落取决于段落何时填充,因此并不可靠。


我一直在遵循这个确切的策略,但是所有段落都会触发Inlines.Count=0。+1 :) - Maverik
看起来有点粗糙,但运行良好!关于Paragraph.Inlines.Count,我不需要这样做,因为我已经知道我的段落中有什么。大多数情况下(在我的情况下),段落只包含一个TextBlock,我知道其中的文本,但隐藏TextBlock仍然会留下空白空间,因为有Paragraph。这就解释了为什么我需要知道如何摆脱这个空间。 - Maxime Tremblay-Savard
确实有点hackish,所以我一开始有些犹豫是否要发布。很高兴它似乎至少是有效的。 - GazTheDestroyer
我会留一些时间给其他人回答,如果没有一个好的答案,我会给你“正确的答案”和赏金。感谢您对我的问题的贡献! - Maxime Tremblay-Savard
没问题。我自己也很感兴趣,想看看是否有一个“合适”的解决方案。 - GazTheDestroyer
考虑到FlowDocument并不是真正的布局组件,我认为唯一“合适”的解决方案就是从文档中删除整个段落。如果这不是一个选择,那么这个解决方案就和其他任何一个一样好。 - almulo

2
如果在您的情况下,可行的做法是使用虚拟机属性指示段落是否为空,则可以这样操作:-
<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>

根据字体大小的不同,您可能需要调整样式中“默认”边距值为“0,0,0,18”的值。

或者,如果可以通过编程确定段落是否为空,您可以创建一个继承的Paragraph控件,该控件公开一个IsEmpty依赖属性。触发器将使用此属性而不是Tag,并且您将不需要VM属性。


"VM属性"中的VM是什么意思? - Maxime Tremblay-Savard
1
@MaximeTremblay-Savard - 视图模型(假设您正在使用MVVM) - Andrew Stephens

1
尝试这个。
<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));
        }
    }

这个方法可以用,但我想知道是否有比完全将该块从其父级中删除更简单的方法。不过还是谢谢你的答案! - Maxime Tremblay-Savard

1
在HTML中,段落标签即使为空也会占用空间,这是因为它是一个块级元素,因此具有布局。这意味着渲染代理为其分配了像填充和行高之类的属性,并且 它将导致换行
您能否找到一种方法来检测段落是否为空并更改其显示规则?可见性不会删除元素,只会使其不可见,因此段落标记仍然会导致那个讨厌的换行符。实际上,先前发布的 line-height 解决方案仍然保留该行断点。(关于 display vs visibility 的文章)
CSS 规则 display:none; 可用于将其从页面流中移除 (请参阅上面的 hasLayout 链接)。我喜欢使用 CSS 类并以编程方式应用它。通常像这样做就可以解决问题:
.hidden {display:none;height:0;width:0;}

你可以在该类中加入line-height:0;,以覆盖先前的建议。

这很有道理,但在WPF应用程序中如何实现呢? - Maxime Tremblay-Savard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接