Reputation: 8550
I need textblock, that could toggle between full text and trimmed text, something like this in a picture:
And could not find anything similar.
Expander is something like that, but it would show trimmed and full version by default (trimmed in header, full in content).
I thought to write something with attached properties, but I need to paint button, check if it needs button at all (text is not trimmed), do the collapse and expand logic - in short I'm feeling like inventing wheel here, someone should have done this before, just probably I can't find it?
Upvotes: 1
Views: 3047
Reputation: 8550
I've combined ideas from two given answers and got quite pleasant result, hope someone will find it useful. Basic idea is, that I'm using empty Expander to toggle TextWrapping for a TextBlock. It needed C# code in single place only - to know if TextBlock is currently trimming text, I've borrowed code from https://stackoverflow.com/a/25436070/212121
<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>
Upvotes: 0
Reputation: 5442
You can use a TextBlock
and just add a button that will toggle it's TextWrapping
property.
<TextBlock Text="{Binding Text}" TextWrapping="{Binding WrapMode}" />
<Button Command="{Binding ToggleWrapMode}" />
Make the button's command toggle between TextWrapping.NoWrap
and TextWrapping.Wrap
. Also, make sure you set the height of the textblock (or it's container) so the wrapping will happen at the size you want.
Update:
In order to find out whether you need the button to be visible, you can initialize WrapMode
to NoWrap
and check if the ActualHeight
of the TextBlock
is higher than the threshold you defined. If it is higher - you put the limitation on the Height
of the TextBlock
, otherwise you just hide the button.
I do find this method quite messy (and might cause a flicker on the screen), I'll try to think of something smarter.
Update 2: As Sinatr suggest in the command, this is a much nicer way to know if your text needs wrapping.
Upvotes: 3
Reputation: 28272
I'd make a usercontrol to handle the case. Should be easy... I've crafted this quickly on a ContentControl
but could be easily expanded to suit your needs:
<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>
And use it like:
<ContentControl Template="{StaticResource MyControl}"/>
Result, expanded:
And contracted:
Of course, you'd need to style it to your needs. Could (and should) make a property to have the text defined in the UserControl and not in the template, the desired contracted height, etc.
Checking if it actually needs a button requires some codebehind (checking if Height
is ActualHeight
comes to mind, but for a better way you'd ideally create a FormattedText
object with the TextBlock
's typeface, apply the same text and check if it's height is the ActualHeight
of the control... I'd put this on an attached dependency property).
Upvotes: 5