Robert Mazurowski Robert Mazurowski - 2 months ago 13
C# Question

String.Format Is it possible to display file name for Path string in XAML

Hi i am new to C# and WPF. The below is just example not tested.

Lets say i have

String path1 = "C:\Users\user\Desktop\File.ext"
String path2 = "C:\temp\text.txt"

String.Format(path1.Substring(path1.LastIndexOf('\')+1))
String.Format(path2.Substring(path1.LastIndexOf('\')+1))


I want to get the filename from the path without changing the original string and i want to do it preferably in XAML or do a value converter.

I am looking into this to know if I should do a value converter between one Observable collection and ListView or just stick with two Lists. One to contain filepaths in model manually and fileNames to display in a ListView and update both separately (Current approach).

My data model

private List<String> AttachedFiles;
public ObservableCollection<String> fileNames { get; set; }

public void addFilePath(String filePath) {
this.AttachedFiles.Add(filePath);
}

public void removeFilePath(String filePath)
{
this.AttachedFiles.Remove(filePath);
}


The xaml

<ListView x:Name="DropList" ItemsSource="{Binding fileNames}"


I included very little code as this as to give an just an idea as I am thinking of refactoring. Can i use String methods inside String.Format for dipsplaying in XAML so it will still have the original filepath value in the model or is there some syntax for String.Format to do this?

EDIT
The answers are duplicated but I was asking if String.Format can be used in the XAML converter with methods like Trim Substring Etc and if I should refactor my code, but doing it properly creates more code and complexity than it removes.

EDIT 2
This is the code. Basically the list view has an X icon and text with file name next it, if the user clicks the icon the it will call this:

private void r1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Rectangle r = sender as Rectangle;
ticket.removeFilePath(r.DataContext.ToString());
ticket.fileNames.Remove(r.DataContext.ToString());
}

Answer

Use one collection, and don't use List<T>:

ObservableCollection<String> FilePaths { get; private set; }

If you replace the collection, you'll need to raise INotifyPropertyChanged.PropertyChanged.

Write a value converter (OK, just steal mine):

public class FileName : MarkupExtension, IValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider) => this;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return System.IO.Path.GetFileName(value.ToString());
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

And use the value converter in a DataTemplate. Since FilePaths is a collection of String, the DataContext of your DataTemplate will be a String, so the binding won't specify a property for the binding to use. The value passed to the value converter will be the string itself.

<ListView x:Name="DropList" ItemsSource="{Binding FilePaths}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Label 
                Content="{Binding Converter={local:FileName}}" 
                />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>