driis
driis

Reputation: 164281

Storing WPF Image Resources

For a WPF application which will need 10 - 20 small icons and images for illustrative purposes, is storing these in the assembly as embedded resources the right way to go?

If so, how do I specify in XAML that an Image control should load the image from an embedded resource?

Upvotes: 458

Views: 524824

Answers (11)

datchung
datchung

Reputation: 4622

Building on the answer by Drew Noakes, here are the complete steps I followed to create a resource dictionary, add a BitmapImage resource to it, and reference the BitmapImage resource in a user control.

  1. Add an Images folder at the project root.
  2. Add MyImage.png under the Images folder.
  3. In the MyImage.png Properties window, set Build Action to Resource.
  4. Create a resource dictionary at the project root named MainResourceDictionary.xaml:
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <BitmapImage x:Key="MyImageSource" UriSource="Images/MyImage.png" />
</ResourceDictionary>
  1. Add a reference to the resource dictionary in the control:
<UserControl ...>
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MainResourceDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    ...
  1. Reference the image resource in the control:
<UserControl ...>
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MainResourceDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    ...
    <Image Source="{DynamicResource ResourceKey=ServiceLevel1Source}" />
    ...

Upvotes: 2

Sanjay Ranavaya
Sanjay Ranavaya

Reputation: 587

Yes, it's the right way. You can use images in the Resource file using a path:

<StackPanel Orientation="Horizontal">
    <CheckBox  Content="{Binding Nname}" IsChecked="{Binding IsChecked}"/>
    <Image Source="E:\SWorking\SharePointSecurityApps\SharePointSecurityApps\SharePointSecurityApps.WPF\Images\sitepermission.png"/>
    <TextBlock Text="{Binding Path=Title}"></TextBlock>
</StackPanel>

Upvotes: 2

Raghulan Gowthaman
Raghulan Gowthaman

Reputation: 468

The following worked and the images to be set is resources in properties:

    var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
                                      IntPtr.Zero,
                                      Int32Rect.Empty,
                                      BitmapSizeOptions.FromEmptyOptions());
    MyButton.Background = new ImageBrush(bitmapSource);
img_username.Source = bitmapSource;

Upvotes: -4

Eric Ouellet
Eric Ouellet

Reputation: 11754

In code to load a resource in the executing assembly where my image Freq.png was in the folder Icons and defined as Resource:

this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
    + Assembly.GetExecutingAssembly().GetName().Name 
    + ";component/" 
    + "Icons/Freq.png", UriKind.Absolute)); 

I also made a function:

/// <summary>
/// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'.
/// </summary>
/// <param name="pathInApplication">Path without starting slash</param>
/// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param>
/// <returns></returns>
public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null)
{
    if (assembly == null)
    {
        assembly = Assembly.GetCallingAssembly();
    }

    if (pathInApplication[0] == '/')
    {
        pathInApplication = pathInApplication.Substring(1);
    }
    return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); 
}

Usage (assumption you put the function in a ResourceHelper class):

this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");

Note: see MSDN Pack URIs in WPF:
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Upvotes: 51

techfan
techfan

Reputation: 691

Full description how to use resources: WPF Application Resource, Content, and Data Files

And how to reference them, read "Pack URIs in WPF".

In short, there is even means to reference resources from referenced/referencing assemblies.

Upvotes: 14

Nuno Rodrigues
Nuno Rodrigues

Reputation: 2122

I found to be the best practice of using images, videos, etc. is:

  • Change your files "Build action" to "Content". Be sure to check Copy to build directory.
    • Found on the "Right-Click" menu at the Solution Explorer window.
  • Image Source in the following format:
    • "/«YourAssemblyName»;component/«YourPath»/«YourImage.png»"

Example

<Image Source="/WPFApplication;component/Images/Start.png" />

Benefits:

  • Files are not embedded into the assembly.
    • The Resource Manager will raise some memory overflow problems with too many resources (at build time).
  • Can be called between assemblies.

Upvotes: 207

user42467
user42467

Reputation: 1951

If you're using Blend, to make it extra easy and not have any trouble getting the correct path for the Source attribute, just drag and drop the image from the Project panel onto the designer.

Upvotes: 4

ema
ema

Reputation: 5773

Yes, it is the right way.

You could use the image in the resource file just using the path:

<Image Source="..\Media\Image.png" />

You must set the build action of the image file to "Resource".

Upvotes: 48

Drew Noakes
Drew Noakes

Reputation: 310792

If you will use the image in multiple places, then it's worth loading the image data only once into memory and then sharing it between all Image elements.

To do this, create a BitmapSource as a resource somewhere:

<BitmapImage x:Key="MyImageSource" UriSource="../Media/Image.png" />

Then, in your code, use something like:

<Image Source="{StaticResource MyImageSource}" />

In my case, I found that I had to set the Image.png file to have a build action of Resource rather than just Content. This causes the image to be carried within your compiled assembly.

Upvotes: 521

JoanComasFdz
JoanComasFdz

Reputation: 3066

  1. Visual Studio 2010 Professional SP1.
  2. .NET Framework 4 Client Profile.
  3. PNG image added as resource on project properties.
  4. New file in Resources folder automatically created.
  5. Build action set to resource.

This worked for me:

<BitmapImage x:Key="MyImageSource" UriSource="Resources/Image.png" />

Upvotes: 8

Craig
Craig

Reputation: 491

Some people are asking about doing this in code and not getting an answer.

After spending many hours searching I found a very simple method, I found no example and so I share mine here which works with images. (mine was a .gif)

Summary:

It returns a BitmapFrame which ImageSource "destinations" seem to like.

Use:

doGetImageSourceFromResource ("[YourAssemblyNameHere]", "[YourResourceNameHere]");

Method:

static internal ImageSource doGetImageSourceFromResource(string psAssemblyName, string psResourceName)
{
    Uri oUri = new Uri("pack://application:,,,/" +psAssemblyName +";component/" +psResourceName, UriKind.RelativeOrAbsolute);
    return BitmapFrame.Create(oUri);
}

Learnings:

From my experiences the pack string is not the issue, check your streams and especially if reading it the first time has set the pointer to the end of the file and you need to re-set it to zero before reading again.

I hope this saves you the many hours I wish this piece had for me!

Upvotes: 49

Related Questions