I want to obtain the overflown text (i.e. the substring after the ellipsis) after setting FormattedText.MaxTextWidth and FormattedText.MaxTextHeight. Is there an elegant way to achieve this? This seems especially diffult since FormattedText may contain different font families, font sizes etc.
Get overflown text of FormattedText
564 views Asked by Fred Nek At
2
There are 2 answers
0
On
Hmm, this was a tough one. I can get it very close, but it's not 100% accurate. However, perhaps you can use this as a starting point.
Example Output for this string: "This is some really long text that cannot fit within the width specified!"
The Approach:
Basically I wrote a while loop that would check the actual formatted text's width when I fed it some text. If the width exceeded the width of the one that was displaying the ellipsis, then I would strip out the last character and check again and again and again until it fit.
MainWindow.xaml:
<Window x:Class="GetOverflowTextTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<RadioButton x:Name="radioButtonArial" Content="Arial Size 14" GroupName="Fonts" Click="ArialClick" Margin="5" IsChecked="True"/>
<RadioButton x:Name="radioButtonTimesNewRoman" Content="Times New Roman Size 32" GroupName="Fonts" Click="TimesNewRomanClick" Margin="5"/>
</StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Long Text Block With Ellipsis (Width 200): " Margin="5" HorizontalAlignment="Right"/>
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="myTextBlock" Width="200" Margin="5" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Background="DarkGreen" Foreground="White" HorizontalAlignment="Left" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Here's your overflow text: " Margin="5" HorizontalAlignment="Right"/>
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="myOverflowTextBlock" Margin="5" TextWrapping="NoWrap" HorizontalAlignment="Left"/>
</Grid>
<StackPanel Orientation="Horizontal">
</StackPanel>
<StackPanel Orientation="Horizontal">
</StackPanel>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Globalization;
using System.Windows;
using System.Windows.Media;
namespace GetOverflowTextTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private const string TEXT = "This is some really long text that cannot fit within the width specified!";
public MainWindow()
{
InitializeComponent();
this.Loaded += OnLoaded;
this.myTextBlock.Text = TEXT;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
UpdateFont();
}
private void UpdateFont()
{
if (this.radioButtonArial.IsChecked.HasValue && this.radioButtonArial.IsChecked.Value)
{
// Change the font to Arial
this.myTextBlock.FontFamily = new FontFamily("Arial");
this.myTextBlock.FontSize = 14;
}
else
{
// Change the font to Times New Roman
this.myTextBlock.FontFamily = new FontFamily("Times New Roman");
this.myTextBlock.FontSize = 32;
}
// Calculate the overflow text using the font, and then update the result.
CalculateAndUpdateOverflowText();
}
private void CalculateAndUpdateOverflowText()
{
// Start with the full text.
var displayedText = TEXT;
// Now start trimming until the width shrinks to the width of myTextBlock.
var fullFormattedText = new FormattedText(displayedText, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(this.myTextBlock.FontFamily, myTextBlock.FontStyle, myTextBlock.FontWeight, myTextBlock.FontStretch), myTextBlock.FontSize, new SolidColorBrush(Colors.Black), 1.0);
while (fullFormattedText.Width > this.myTextBlock.Width)
{
displayedText = displayedText.Remove(displayedText.Length - 1, 1);
fullFormattedText = new FormattedText(displayedText, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(this.myTextBlock.FontFamily, myTextBlock.FontStyle, myTextBlock.FontWeight, myTextBlock.FontStretch), myTextBlock.FontSize, new SolidColorBrush(Colors.Black), 1.0);
}
// What you have left is the displayed text. Remove it from the overall string to get the remainder overflow text.
// The reason why I added "- 3" is because there are three ellipsis characters that cover up some of the text that would have otherwise been displayed.
var overflowText = TEXT.Remove(0, displayedText.Length - 3);
// Update the text block
this.myOverflowTextBlock.Text = overflowText;
}
private void ArialClick(object sender, RoutedEventArgs e)
{
UpdateFont();
}
private void TimesNewRomanClick(object sender, RoutedEventArgs e)
{
UpdateFont();
}
}
}

After thinking about this problem for a little more, I've come up with this solution (which returns the index of the first :