I would like to show ellipsis if my filename and path do not fit in a TextBlock
.
For example, if my file name and path are like:
C:\examples\example\folderA\folderB\folderC\myfilename.txt
I would like to show it in my TextBlock
like this:
C:\examples...myfilename.txt
UPDATE:
I know I can use TextTrimming
to set ellipsis at the end. But I need a way to set ellipsis in the middle somewhere.
Ok, I was interested if this could be done with just basic XAML, and no messing around with measuring or drawing, so started messing around. I don't have time to finish this today, but I thought I'd share as a starting point for you if you'd like to take it and clean it the remaining issue.
The XAML looks like this so far :
<Window.Resources>
<local:FileNameConverter x:Key="FileNameConverter" />
<local:FilePathConverter x:Key="FilePathConverter" />
<Style x:Key="CustomFileText" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocused, RelativeSource={RelativeSource Self}}" Value="false">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<TextBox IsHitTestVisible="False" /> <!-- for Border -->
<DockPanel>
<TextBlock Text="{TemplateBinding Text, Converter={StaticResource FileNameConverter}}" DockPanel.Dock="Right" Margin="-3,3,4,3" />
<TextBlock Text="{TemplateBinding Text, Converter={StaticResource FilePathConverter}}" TextTrimming="CharacterEllipsis" Margin="4,3,0,3" />
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBox Text="C:\Program Files\Some Directory\SomeFile.txt" Style="{StaticResource CustomFileText}"/>
<TextBox Margin="0,10" />
</StackPanel>
The end result is that if the TextBox has focus for editing, it displays as a normal TextBox :
But once the user moves their focus elsewhere on the form, it splits up into two separate TextBlocks that uses converters to parse the Directory and FileName. TextTrimming is used on the Directory to give the effect you were describing in your question :
The main problem with this is when resizing, the extra space is added between the two textboxes.
There's two options I can think of here :
Make the template based on a Trigger of some kind that says "only use this template if TextBox.DesiredSize.Width > TextBox.ActualWidth
"
Change the XAML in the template so the Name TextBox somehow says "take up all the space you need as your minimum size. If there is extra space, assign it to this box too", while the Directory TextBox says "take up all the space you can, but do not grow bigger than your contents". I am not sure the best way to do this, but I imagine it has something to do with either a different panel, some properties on TextBox I can't think of right now, or some custom converter/binding to limit size.
I am guessing #1 will be easier to implement, but I don't have time to figure it out now. Hope this gives you a good starting point though, and good luck with it! :)
Oh, and converters were just very basic. You'd probably want to add more safeguards, but here's what I was using for testing :
public class FileNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value is string)
return System.IO.Path.GetFileName((string)value);
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class FilePathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value is string)
return System.IO.Path.GetDirectoryName((string)value);
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I modified XAML provided by Rachel to fix the extra space in the path appearing on window sizing.
<Window.Resources>
<local:FileNameConverter x:Key="FileNameConverter" />
<local:FilePathConverter x:Key="FilePathConverter" />
<Style x:Key="CustomFileText" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocused, RelativeSource={RelativeSource Self}}" Value="false">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<TextBox Grid.ColumnSpan="2" IsHitTestVisible="False"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="{Binding ActualWidth, ElementName=PART_DirMaxWidth}"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Canvas x:Name="PART_Canvas">
<TextBlock x:Name="PART_DirMaxWidth" Margin="0" Padding="0" Text="{TemplateBinding Text, Converter={StaticResource FilePathConverter}}" Visibility="Hidden"/>
<TextBlock Width="{Binding ActualWidth, ElementName=PART_Canvas}" Margin="0" Padding="0" Text="{TemplateBinding Text, Converter={StaticResource FilePathConverter}}" TextTrimming="CharacterEllipsis" Background="Transparent"/>
</Canvas>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Margin="0" Padding="0" Text="\" Background="Transparent"/>
<TextBlock Margin="0" Padding="0" Text="{TemplateBinding Text, Converter={StaticResource FileNameConverter}}" Background="Transparent"/>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With