30

I'm trying to programmatically load a BitmapImage in a XAML Metro app. Here's my code:

var uri = new Uri("/Images/800x600/BackgroundTile.bmp", UriKind.RelativeOrAbsolute);
var imageSource = new BitmapImage(uri);

The second line crashes with a System.ArgumentException:

The given System.Uri cannot be converted into a Windows.Foundation.Uri. Please see http://go.microsoft.com/fwlink/?LinkID=215849 for details.

The link just goes to the MSDN home page, so it's no use.

I've also tried removing the leading /, in case WinRT has different expectations about relative URIs, but I still get the same exception.

Why am I getting this exception for what seems to be a perfectly valid URI?

Joe White
  • 94,807
  • 60
  • 220
  • 330
  • Have you tried new'ing up such a Foundation Uri? Is it possible? – flq Sep 27 '11 at 13:15
  • There doesn't seem to *be* a Windows.Foundation.Uri class. It's documented (http://msdn.microsoft.com/en-us/library/windows/apps/windows.foundation.uri(v=vs.85).aspx), but when I try `new Windows.Foundation.Uri()`, VS2011 shows a red squiggly underline under "Uri" with tooltip "The type or namespace 'Uri' does not exist in the namespace 'Windows.Foundation' (are you missing an assembly reference?)". This is in my UI assembly, so it should already have all the references that matter. – Joe White Sep 27 '11 at 13:24
  • 1
    @Joe the class is there in WinRT, but .NET projection hides it from you, just as it hides e.g. `IIterable` or `IVector`. You are, indeed, supposed to just use `System.Uri`. – Pavel Minaev Sep 27 '11 at 15:44
  • System.Uri is convertible into Windows.Foundation.Uri. That is why you are getting a runtime error and not a compile time one. – Steve Rowe Sep 27 '11 at 15:57
  • 1
    @PavelMinaev I thought the projections were supposed to unify the platforms, not divide them. Why are there both a System.Uri and a Windows.Foundation.Uri with lossy conversions at runtime? Is that just because this is a developer preview, or is it going to be that bad in the shipping product? – Joe White Sep 27 '11 at 15:59
  • @Joe There is no `Windows.Foundation.Uri` in .NET projection - that is the point. For a .NET developer, it simply doesn't exist. The platform _is_ unified: if you write a C++/CX component that takes `Windows.Foundation.Uri`, you see it as taking `System.Uri` from .NET. The reason why `System.Uri` is kept is the same as why existing .NET collection interfaces are kept - so that more existing .NET code works. Unification is about behavior, not about names. – Pavel Minaev Sep 27 '11 at 20:36
  • 1
    @Joe Also it's not a lossy conversion (since it didn't actually let you convert it). Treat it as a precondition: any WinRT method that takes an `Uri` expects an absolute `Uri`. In .NET terms, it's as if it had `if (uri.IsAbsoluteUri) throw new ArgumentException()` - which is perfectly valid, and often quite reasonable, in .NET. – Pavel Minaev Sep 27 '11 at 20:38

7 Answers7

34

In the Consumer Preview, the correct URL format has apparently changed to ms-appx:/Images/800x600/BackgroundTile.bmp

Sander
  • 25,685
  • 3
  • 53
  • 85
  • Can you link to some docs? I see from "[How to reference content](http://msdn.microsoft.com/en-us/library/windows/apps/hh781215.aspx)" that `ms-appx` works from JavaScript, but does it work for XAML-based UIs as well? – Joe White Mar 05 '12 at 14:01
  • Yes, I can confirm that it works for XAML-based UIs, as well. I have not found any documentation on it - only trial and error led me to this result. – Sander Mar 05 '12 at 14:09
  • I'm being asked to "find an app" to open the URI instead of navigating to the resource. Any ideas? this.webBrowser.Navigate(new Uri("ms-appx://Assets/HTML/HelpPage/help.html")); (I've tried with 1, 2, and 3 leading forward slashes to no avail as well) – matthewsheets Jun 10 '15 at 17:19
17

Judging from the documentation for Windows.Foundation.Uri, it looks like WinRT doesn't support relative URIs. I tried a pack:// URI, but that gave me a UriFormatException, so apparently that's not the way to do it in WinRT either.

I found the answer on this thread: MS invented yet another URI format for WinRT resources. This works:

new Uri("ms-resource://MyAssembly/Images/800x600/BackgroundTile.bmp")

Note that you don't add your actual assembly name -- the MyAssembly part is literal text.

Joe White
  • 94,807
  • 60
  • 220
  • 330
3

You will need to use the page's BaseUri property or the image control's BaseUri property like this:

//using the page's BaseUri property
BitmapImage bitmapImage = new BitmapImage(this.BaseUri,"/Images/800x600/BackgroundTile.bmp");
image.Source = bitmapImage;

or

//using the image control's BaseUri property
image.Source = new BitmapImage(image.BaseUri,"/Images/800x600/BackgroundTile.bmp");

you can see the reason and solution here

Sunday Okpokor
  • 721
  • 6
  • 18
0

In case you're still having issues or are being asked to find an app to open the link, are you trying to use a WebView? If so, try using ms-appx-web instead of ms-appx.

An example:

this.webBrowser.Navigate(new Uri("ms-appx-web:///level/level/level/index.html"));

Also note the lack of the URIKind parameter--evidently not needed at all in these instances.

(I believe you may need to vary the leading forward slashes depending on your reference)

matthewsheets
  • 4,535
  • 2
  • 15
  • 11
0

This would work in XAML but would not work in code... so each control or page has a BaseUri property which you can use to build the proper uri for assets... here is an example:

    imageIcon.Source = new BitmapImage(new Uri(this.BaseUri, "Assets/file.gif"));

// Or use the base uri from the imageIcon, same thing

    imageIcon.Source = new BitmapImage(new Uri(imageIcon.BaseUri, "Assets/file.gif"));

also you would need to set the build action to "Content" rather than Embedded Resource... otherwise you need to use the ms-resource:// protocol.

Zia Ur Rahman
  • 1,850
  • 1
  • 21
  • 30
0

I know this is old but I hope this helps. I wrote this in XAML and it worked for me. The Ide I'm using is vs-2015 with win-10.

<Window>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="NameOfYourImage.JPG or any Image type"/>
</Grid.Background>
<GroupBox x:Name="groupBox" Header="GroupBox" HorizontalAlignment="Left"   Height="248" Margin="58,33,0,0" VerticalAlignment="Top" Width="411">
<GroupBox.Background>
<ImageBrush ImageSource="NameOfYourImage.JPG or any Image type"/>
</GroupBox.Background>
</GroupBox>
</Grid>
</Window>
  • 1
    I think you missed the point of the question. Of course it works in XAML. The question wasn't *about* referencing images in XAML. It was about referencing images in *code.* – Joe White Jan 21 '17 at 00:25
0

MVVM ;)

    public static ImageSource SetImageSource(string uriPath)//.com/image or some path
    {
        // this method very good for mvvm ;)
        try
        {   
            //In Model - public ImageSource AccountPhoto { get; set; } 
            //AccountPhoto = SetImageSource("some path");
            return return new BitmapImage()
            {
                CreateOptions = BitmapCreateOptions.IgnoreImageCache,
                UriSource = new Uri(uriPath)
            };
        }
        catch
        {
            Debug.WriteLine("Bad uri, set default image.");
            return return new BitmapImage()
            {
                CreateOptions = BitmapCreateOptions.IgnoreImageCache,
                UriSource = new Uri("ms-appx:///Avatar/Account Icon.png")
            };
        }
    }