Wrap TextBlock 的最大行数

Posted

技术标签:

【中文标题】Wrap TextBlock 的最大行数【英文标题】:Maximum number of lines for a Wrap TextBlock 【发布时间】:2012-11-18 05:40:59 【问题描述】:

我有一个TextBlock,其设置如下:

TextWrapping="Wrap"

我可以确定最大行数吗?

例如考虑以下字符串TextBlock.Text

This is a very good horse under the blackboard!!

目前有这样的节目:

This is a very 
good horse under 
the blackboard!!

我需要它变成这样:

This is a very 
good horse ...

有什么办法吗?

【问题讨论】:

【参考方案1】:

您需要在TextBlock 中设置TextTrimming="WordEllipsis"

【讨论】:

谢谢,但这仅在文本到达 TextBlock 的末尾时才有效,这可能是 2 行或更多行。我希望TextBlock 在例如之后修剪文本正好 2 行。 @MBZ 为此,您需要编写自定义转换器,该转换器会遍历您的 TextBlock 文本并在需要的地方插入省略号。 如果你可以设置文本块的高度,修剪和环绕设置应该是你所需要的全部【参考方案2】:

我怀疑这是可配置的,换行基于许多因素,例如字体大小/字距调整、文本块的可用宽度(horizo​​ntalalignment=stretch 可以产生很大的不同)、父面板类型(scrollviewer/stackpanel/grid ) 等。

如果您希望文本明确地流到下一行,您应该使用“运行”块,然后对该运行块使用类型省略号的换行。

【讨论】:

请看下面@kindasimple 的评论,这会给你想要的。 为什么选择这个作为答案?【参考方案3】:

更新(针对 UWP)

在 UWP 应用中你不需要这个并且可以使用 TextBlock 属性MaxLines(参见MSDN)


原答案:

如果您有特定的LineHeight,您可以计算 TextBlock 的最大高度

示例:

最多 3 行的文本块

<TextBlock 
  Width="300"
  TextWrapping="Wrap" 
  TextTrimming="WordEllipsis" 
  FontSize="24" 
  LineStackingStrategy="BlockLineHeight"
  LineHeight="28"
  MaxHeight="84">YOUR TEXT</TextBlock>

这就是满足您的要求所需要的一切。

如何动态地做到这一点?

只需在 C#/VB.NET 中创建一个扩展 TextBlock 的新控件,并为其赋予一个新的 DependencyProperty int MaxLines。 然后重写OnApplyTemplate()方法,并根据LineHeight * MaxLines设置MaxHeight

这只是关于如何解决这个问题的基本解释!

【讨论】:

【参考方案4】:

如果您已设置好 HeightTextWrappingTextTrimming,它将完全按照您的意愿行事:

<TextBlock Height="60" FontSize="22" FontWeight="Thin"
    TextWrapping="Wrap" TextTrimming="CharacterEllipsis">

上面的代码最多会换行两行,然后在此之后使用CharacterEllipsis

【讨论】:

【参考方案5】:

根据@artistandsocial 的回答,我创建了一个附加属性来以编程方式设置最大行数(而不是在 WPF 中不鼓励重载 TextBlock)。

public class LineHeightBehavior

    public static readonly DependencyProperty MaxLinesProperty =
        DependencyProperty.RegisterAttached(
            "MaxLines",
            typeof(int),
            typeof(LineHeightBehavior),
            new PropertyMetadata(default(int), OnMaxLinesPropertyChangedCallback));

    public static void SetMaxLines(TextBlock element, int value) => element.SetValue(MaxLinesProperty, value);

    public static int GetMaxLines(TextBlock element) =>(int)element.GetValue(MaxLinesProperty);

    private static void OnMaxLinesPropertyChangedCallback(
        DependencyObject d, 
        DependencyPropertyChangedEventArgs e)
    
        if (d is TextBlock textBlock)
        
            if (textBlock.IsLoaded)
            
               SetLineHeight();
            
            else
            
                textBlock.Loaded += OnLoaded;

                void OnLoaded(object _, RoutedEventArgs __)
                
                    textBlock.Loaded -= OnLoaded;
                    SetLineHeight();
                
            

            void SetLineHeight()
            
                double lineHeight =
                   double.IsNaN(textBlock.LineHeight)
                        ? textBlock.FontFamily.LineSpacing * textBlock.FontSize
                        : textBlock.LineHeight;
                textBlock.MaxHeight = Math.Ceiling(lineHeight * GetMaxLines(textBlock));
            
        
    

默认情况下LineHeight设置为double.NaN,所以这个值必须先手动设置,否则根据TextBlockFontFamilyFontSize计算高度。

然后可以在Style 中设置附加属性MaxLines 和其他相关属性:

<Style TargetType="x:Type TextBlock"
       BasedOn="StaticResource x:Type TextBlock">
    <Setter Property="TextTrimming"
            Value="CharacterEllipsis" />
    <Setter Property="TextWrapping"
            Value="Wrap" />
    <Setter Property="LineHeight"
            Value="16" />
    <Setter Property="LineStackingStrategy"
            Value="BlockLineHeight" />
    <Setter Property="behaviors:LineHeightBehavior.MaxLines"
            Value="2" />
</Style>

【讨论】:

【参考方案6】:

对于开发 UWP 或 WinRT 应用程序的任何人,TextBlock 具有您可以设置的 MaxLines 属性。

【讨论】:

【参考方案7】:

基于 tobi.at 和 gt 的回答,我创建了这个 MaxLines 行为。至关重要的是,它不依赖于通过计算字体的行高来设置LineHeight 属性。您仍然需要设置 TextWrappingTextTrimming 以使其 TextBox 可以根据需要进行渲染。

<TextBlock behaviours:NumLinesBehaviour.MaxLines="3" TextWrapping="Wrap" TextTrimming="CharacterEllipsis" Text="Some text here"/>

还有一个MinLines 行为,它可以与MaxLines 行为不同或设置为相同的数字来设置行数。

public class NumLinesBehaviour : Behavior<TextBlock>

    TextBlock textBlock => AssociatedObject;

    public static readonly DependencyProperty MaxLinesProperty =
        DependencyProperty.RegisterAttached(
            "MaxLines",
            typeof(int),
            typeof(NumLinesBehaviour),
            new PropertyMetadata(default(int), OnMaxLinesPropertyChangedCallback));

    public static void SetMaxLines(DependencyObject element, int value)
    
        element.SetValue(MaxLinesProperty, value);
    

    public static int GetMaxLines(DependencyObject element)
    
        return (int)element.GetValue(MaxLinesProperty);
    

    private static void OnMaxLinesPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        TextBlock element = d as TextBlock;
        element.MaxHeight = getLineHeight(element) * GetMaxLines(element);
    

    public static readonly DependencyProperty MinLinesProperty =
        DependencyProperty.RegisterAttached(
            "MinLines",
            typeof(int),
            typeof(NumLinesBehaviour),
            new PropertyMetadata(default(int), OnMinLinesPropertyChangedCallback));

    public static void SetMinLines(DependencyObject element, int value)
    
        element.SetValue(MinLinesProperty, value);
    

    public static int GetMinLines(DependencyObject element)
    
        return (int)element.GetValue(MinLinesProperty);
    

    private static void OnMinLinesPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        TextBlock element = d as TextBlock;
        element.MinHeight = getLineHeight(element) * GetMinLines(element);
    

    private static double getLineHeight(TextBlock textBlock)
    
        double lineHeight = textBlock.LineHeight;
        if (double.IsNaN(lineHeight))
            lineHeight = Math.Ceiling(textBlock.FontSize * textBlock.FontFamily.LineSpacing);
        return lineHeight;
    

【讨论】:

在删除了不必要的东西后,比如“: Behavior”和下面的代码行,显然是从 Behavior 基类派生的,它就像一个魅力。所以只使用静态类,带有dependencyProperties。

以上是关于Wrap TextBlock 的最大行数的主要内容,如果未能解决你的问题,请参考以下文章

Windows 8.1 应用程序:使用换行、最大行数或最大高度识别 TextBlock 的 UI 文本截断

Windows 8 ScrollViewer 打破 TextBlock Wrap

WPF textblock 我想给它的背景绘制个边框和一个填充,怎么设计样式

调整UILabel的大小以适应Word Wrap

Xaml TextBlock 设置圆角

wpf textblock 长文本滚动