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();
}
}
IValueConverter
(orIMultiValueConverter
) that measures if the text fits in the box. If not, convert text into something that fits and contains your rules. Perhaps usePath.GetFileName(..)
to obtain just the file name part, remove it from the full string, and try to trim the remaining string to fit the size for the TextBox. – Pestilence