Search code examples
c#wpfimagexamlembedded-resource

XamlParseException at runtime. Switching from x:Static to a relative component string to reference an image fixes it. Why?


I'm designing my first major app using WPF/C# and I'm trying to understand referencing Resources better.

Many guides tell me to use the first way I am failing to use.

  • I design a resource in illustrator
  • make it 96 dpi,
  • save it as a png,

Then I:

  • Open Resources.resx
  • Click Add Resource ->Image
  • Select my existing PNG called "SuperInt_Alert"
  • Change the build type of that new png to Resource

Then when I try to show the image in my xaml, I use this:

xmlns:prop="clr-namespace:Stark.Properties"

<...code...>

<Image Source="{x:Static prop:Resources.SuperInt_Alert}"  HorizontalAlignment="Center" VerticalAlignment="Top"
               Grid.Row="1"
               Grid.Column="1"
               ></Image>

Gives me a System.Windows.Markup.XamlParseException with Message='Provide value on 'System.Windows.Markup.StaticExtension' threw an exception.'. The Xaml designer also doesn't show my image. It's blank, but no errors.

While

<Image Source="/Stark;component/Resources/SuperInt_Alert.png"  HorizontalAlignment="Center" VerticalAlignment="Top"
       Grid.Row="1"
       Grid.Column="1"
       ></Image>

Works just fine. It even shows it in my designer.

Why?

I'm just trying to understand the differences between the two ways to use a resource. What is wrong with the first way. I actually like the first way better, because when I type in the resource name, it lets me use IntelliSense to auto-complete my resource name. The second way does not because it is like a string.

Also, I do not have to set the resource type to Public, correct? I can leave it as internal because no other projects is using my resource file? I just have to make sure the build type is set to Resource/Content/Embedded Resource, correct?

Thanks so much!


Solution

  • Yes, I certainly agree that this option: Source="{x:Static prop:Resources.SuperInt_Alert}" is better. And yes, you may and you should use it. And you correctly mentioned the cause of your problem. To be able to refer from XAML to property from resources you have to make them public - making them internal generates XamlParseException, you've mentioned. I am not 100% sure why it is but I assume this is because Xaml needs to be parsed. It is parsed by external assemblies. And to obtain proper value code from those assemblies needs to refer to Resources in your project, but they are internal, so normally not accessible outside of the assembly.

    Additionally you will need to convert Bitmap object loaded from resources to ImageSource. To do this you may use Binding and apply there proper converter. Here is exemplary converter class:

    public class BitmapToImageSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            MemoryStream ms = new MemoryStream();
            ((System.Drawing.Bitmap)value).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            image.StreamSource = ms;
            image.EndInit();
    
            return image;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The above class is taken from http://www.shujaat.net/2010/08/wpf-images-from-project-resource.html You will need to add BitmapToImageSourceConverter to resources in your Window:

    <Window.Resources>
        <my:BitmapToImageSourceConverter x:Key="imageSourceConverter"/>
    </Window.Resources>
    

    Here is how you you should define your Image to make use of the converter:

     <Image Source="{Binding Source={x:Static prop:Resources.Picture1}, Converter={StaticResource imageSourceConverter}}"/>