WPF 中的可扩展文本块

Expandable TextBlock in WPF

我需要文本块,它可以在全文和修剪文本之间切换,就像图片中的这样:

找不到类似的东西。

Expander 类似,但它会默认显示修剪版和完整版(在 [=21= 中修剪过,内容完整)。

我想写一些带有附加属性的东西,但我需要绘制按钮,检查它是否需要按钮(文本未被修剪),执行折叠和展开逻辑 - 简而言之,我想发明轮到这里,之前应该有人做过,只是我可能找不到了?

您可以使用 TextBlock 并添加一个按钮来切换 TextWrapping 属性。

<TextBlock Text="{Binding Text}" TextWrapping="{Binding WrapMode}" />
<Button Command="{Binding ToggleWrapMode}" />

使按钮的命令在 TextWrapping.NoWrapTextWrapping.Wrap 之间切换。另外,请确保设置文本块(或其容器)的高度,以便按您想要的大小进行换行。

更新: 为了找出你是否需要按钮可见,你可以将 WrapMode 初始化为 NoWrap 并检查 TextBlockActualHeight 是否高于你设置的阈值定义。如果它更高 - 你把限制放在 TextBlockHeight 上,否则你只是隐藏按钮。

我确实觉得这个方法很乱(而且可能会导致屏幕闪烁),我会试着想出更聪明的方法。

更新二: 正如 Sinatr 在命令中建议的那样,this 是了解文本是否需要换行的更好方法。

我会创建一个用户控件来处理这种情况。应该很容易...我已经在 ContentControl 上快速制作了这个,但可以轻松扩展以满足您的需求:

<ControlTemplate x:Key="MyControl" TargetType="ContentControl">
  <StackPanel>
    <Expander x:Name="ExpanderControl" IsExpanded="True"/>
    <TextBlock x:Name="MyTextBlock" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ex est, hendrerit a ante nec, molestie aliquet nunc. Mauris est mi, aliquam nec nulla id, placerat vulputate est. Nulla tristique elit eu sapien ultrices fringilla. Nulla ac dictum lorem, ac mattis elit. Sed augue arcu, bibendum nec mauris nec, volutpat pulvinar lacus. Mauris et volutpat nibh, eu luctus leo. Pellentesque non dapibus nisi.
Quisque in nulla eu purus sagittis bibendum. Pellentesque orci ipsum, porttitor vitae risus at, faucibus pellentesque justo. Aenean ut nibh pharetra orci euismod vehicula. Aenean commodo vestibulum placerat. Nam condimentum dictum purus nec suscipit. Duis semper ligula massa, in pretium diam scelerisque tincidunt. Vivamus placerat porttitor orci et finibus.
Aenean ut purus eu mi venenatis dapibus id vel urna. Donec enim odio, molestie sed pharetra vel, blandit non purus. Sed in leo eget felis suscipit consectetur. Suspendisse sagittis, sapien ac iaculis venenatis, velit purus viverra turpis, vitae suscipit mi odio pellentesque velit. Proin pulvinar sem consequat nunc varius semper. Maecenas vitae nisl quis risus auctor suscipit. Aenean libero tortor, placerat non ex et, gravida efficitur sem. Aliquam volutpat mauris fermentum, rhoncus arcu et, finibus tortor.
Praesent sit amet pretium risus. Quisque bibendum nibh vel risus rhoncus eleifend. Nunc in eros sit amet neque euismod laoreet. Aliquam dictum ac magna quis interdum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis varius diam dolor, mollis tristique nisl malesuada ac. Nulla sed vehicula sapien. Vestibulum venenatis lobortis sodales. Aliquam rhoncus metus at velit accumsan, at fringilla sapien condimentum. Aliquam erat volutpat. Aenean iaculis mi augue, quis bibendum nibh suscipit ut. Nam commodo, arcu et gravida accumsan, magna diam rhoncus ante, quis posuere nibh tortor nec ligula. Quisque id metus lacus. Quisque ac magna vel ligula commodo tempor. Nam scelerisque fringilla commodo. Curabitur volutpat libero ac metus aliquam, in egestas ipsum luctus.
Ut fringilla lacinia efficitur. Nulla odio tortor, eleifend sed porttitor ut, accumsan sed nunc. Morbi malesuada nisl in lobortis auctor. Nam suscipit neque ac neque blandit dictum. Duis pulvinar commodo enim eget laoreet. In sodales arcu nisl, sit amet posuere orci blandit nec. Nullam a dapibus est, lacinia maximus ante. Mauris rutrum ex nunc, non vehicula orci volutpat vehicula. Praesent mattis tortor non odio molestie, sit amet congue urna sollicitudin. Sed lobortis est et mauris suscipit mattis. Maecenas porttitor elit nec nulla pulvinar, nec porttitor odio placerat. Vivamus maximus lobortis erat a fringilla. Sed vitae hendrerit tortor." />
  </StackPanel>
  <ControlTemplate.Triggers>
    <Trigger SourceName="ExpanderControl" Property="IsExpanded" Value="False">
      <Trigger.Setters>
        <Setter TargetName="MyTextBlock" Property="Height" Value="100"/>
      </Trigger.Setters>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

并像这样使用它:

<ContentControl Template="{StaticResource MyControl}"/>

结果,扩展:

并签约:

当然,您需要根据自己的需要设置样式。可以(并且应该)制作一个 属性 以在 UserControl 而不是在模板中定义文本、所需的收缩高度等。

检查它是否真的需要一个按钮需要一些代码隐藏(想到检查 Height 是否是 ActualHeight,但为了更好的方法,您最好创建一个 FormattedText 对象使用 TextBlock 的字体,应用相同的文本并检查它的高度是否是控件的 ActualHeight...我将其放在附加的依赖项 属性 上)。

我结合了两个给定答案的想法并得到了令人满意的结果,希望有人会发现它有用。 基本思想是,我使用空扩展器来切换 TextBlock 的 TextWrapping。 它只需要一个地方的 C# 代码——要知道 TextBlock 当前是否正在修剪文本,我从

那里借用了代码
<ControlTemplate x:Key="ExpandableTextBlock" TargetType="ContentControl">
        <Grid Focusable="False" Background="Transparent" Margin="4" VerticalAlignment="Center">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition x:Name="ExpandButtonColumnDefinition">
                    <ColumnDefinition.Style>
                        <Style TargetType="{x:Type ColumnDefinition}">
                            <Setter Property="Width" Value="50" />
                            <Style.Triggers>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=TextBlock, Path=(wpfApplication8:TextBlockService.IsTextTrimmed)}" Value="False" />
                                        <Condition Binding="{Binding ElementName=TextBlock, Path=TextWrapping}" Value="NoWrap" />
                                    </MultiDataTrigger.Conditions>
                                    <MultiDataTrigger.Setters>
                                        <Setter Property="Width" Value="0" />
                                    </MultiDataTrigger.Setters>
                                </MultiDataTrigger>                                 
                            </Style.Triggers>
                        </Style>
                    </ColumnDefinition.Style>
                </ColumnDefinition>
            </Grid.ColumnDefinitions>
            <StackPanel x:Name="ViewPort" Orientation="Vertical" Margin="1" VerticalAlignment="Center" Grid.Column="0">
                <TextBlock x:Name="TextBlock" TextTrimming="CharacterEllipsis" Text="{TemplateBinding Content}" />                  
            </StackPanel>
            <Expander Grid.Column="1" x:Name="TextExpander" />                  
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger SourceName="TextExpander" Property="IsExpanded" Value="True">
                <Setter TargetName="TextBlock" Property="TextWrapping" Value="Wrap" />
            </Trigger>
            <Trigger SourceName="TextExpander" Property="IsExpanded" Value="False">
                <Setter TargetName="TextBlock" Property="TextWrapping" Value="NoWrap" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>