views:

138

answers:

2

I have an IValueConverter in WPF that converts a relative file path to a BitmapImage.

The Code:

public class RelativeImagePathToImage : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var relativePath = (string)value;
        if (string.IsNullOrEmpty(relativePath)) return Binding.DoNothing;
        var path = "pack://application:,,,/" + value;
        var uri = new Uri(path);
        return new BitmapImage(uri);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

The Problem:

This converter was working just fine until I tried to use it with a file that was added to the project as a link (Solution Explorer -> Add Existing Item -> Add As Link). The image file's BuildAction is set to Content, and the file is marked Copy Always. The file is definitely getting copied properly to the "bin" folder, but for some reason, the converter chokes when it gets to return new BitmapImage(uri).

The Exception:

System.IO.IOException was unhandled
Message="Cannot locate resource 'images/splash.png'."
Source="PresentationFramework"

Questions:

Can someone explain this? Is this a bug in the .NET Framework or is it expected behavior? Is there a workaround or is "Add As Link" just not an option for image content files?

Edit:

Okay, I found a workaround. Here's my revised converter class:

public class RelativeImagePathToImage : IValueConverter
{
    private static string _rootPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var relativePath = (string)value;
        if (string.IsNullOrEmpty(relativePath)) return Binding.DoNothing;
        var path = _rootPath + "/" + relativePath;
        var uri = new Uri(path);
        return new BitmapImage(uri);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

Apparently, there is some kind of problem with using a packuri with a linked file. But why?

A: 

pack:// uri scheme is only used for files inside resource directories, where else if you just add a file or add a file as a link and set its type to "content" it will only copy the file in your bin folder but it will not be packed inside application resource directories.

So for the file that exists in directory as individual file, you can not use pack uri scheme, you have to use file uri scheme that is normal path. This behaviour is not dependent if file is added as a link or copied, it is dependent on how the file is exported.

Akash Kava
But the code works fine for an image file placed in the folder and set to `Content` - `Copy Always`. It only stopped working when I used a link instead of storing the file in the folder.
DanM
A: 

The answer is to use pack://siteoforigin:,,,/ rather than pack://application:,,,/.

pack://siteoforigin works with any content file that gets copied to the bin/Debug or bin/Release folder (or any sub-folder within), whether the file was added to the project as a link or normally.

path://application only works for content files that are added normally (not as a link).

DanM