WPF图像资源


408

我主要来自网络和一点Windows Forms背景。对于一个新项目,我们将使用WPF。WPF应用程序将需要10-20个小图标和图像以用于说明目的。我正在考虑将它们作为嵌入式资源存储在程序集中。那是正确的路吗?

如何在XAML中指定图像控件应从嵌入式资源加载图像?

Answers:


473

如果要在多个地方使用图像,那么仅将图像数据加载到内存中一次,然后在所有Image元素之间共享就值得了。

为此,请在以下位置创建一个BitmapSource 作为资源:

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

然后,在您的代码中,使用类似以下内容的代码:

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

就我而言,我发现必须将Image.png文件设置为具有Resource而不是的构建动作Content。这将导致图像在已编译的程序集中进行。


6
有可能动态地做到这一点吗?如果我要在启动时加载不同数量的图像,是否可以为每个图像创建BitmapSource并以与上述相同的方式引用它们?
贝基·富兰克林

2
@Becky-是的,可以,但是如果您想在Xaml中引用它们,则可能需要使用DynamicResource标记扩展而不是StaticResource,假设您在编译时就知道键。在WPF中,您可以在运行时创建资源字典。实际上,这就是您加载Xaml文档时发生的情况,只是您没有看到等效的C#。
德鲁·诺阿克斯

9
我遇到的事情:如果将图像资源添加到资源字典中,请不要忘记在XAML中为您的组件引用该图像字典。类似于:<UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source =“ Dictionary1.xaml” /> </ResourceDictionary.MergedDictionaries> </ ResourceDictionary> </UserControl.Resources>
Dan Mitchell,2010年

4
我通常添加Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" Image,否则我经常看到的图像越来越荒唐放大出于某种原因(如16×16的图标延伸到东西,看起来像200x200像素)。
OR Mapper 2014年

5
我发现,如果在引用程序集的resourcedictionary中声明了BitmapImage,则UriSource必须是packURI才能起作用。否则,您会发现在VS中的xaml编辑器中可以看到该图像,但是在调试时看不到任何图像。打包URIS:msdn.microsoft.com/zh-cn/library/aa970069
v=vs.100).aspx

174

我发现使用图像,视频等的最佳做法是:

  • 将文件“构建操作”更改为“内容”。确保选中“ 复制到构建目录”
    • 在“解决方案资源管理器”窗口的“右键单击”菜单上找到。
  • 图像源格式如下:
    • “ / «YourAssemblyName» ;组件/«YourPath»/«YourImage.png»

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

优点:

  • 文件未嵌入到程序集中。
    • 资源管理器会在资源过多时(在构建时)引发一些内存溢出问题。
  • 可以在程序集之间调用。

36
如果将资源嵌入到程序集中,则可以使用相同的方法,但是必须将“生成操作”设置为“资源”。
Ashley Davis 2010年

5
工作,谢谢。其他注意事项:“组件”是“原样”必需的,“图像”是png在项目中的相对路径。即放在根目录中的图像将是“ <Image Source =“ / WPFApplication; component / Start.png” />“
Badiboy 2011年

3
一个用C#做到这一点的例子将是不错的。(这不是有效的URI,因此在构造BitmapImage时无法使用。)
Vaccano 2012年

5
因此,如果文件设置为“嵌入式资源”,该怎么办?这似乎不起作用。而且我不想将图像两次包含在我的项目中。(我已经在使用它作为嵌入式资源。)
BrainSlugs83

2
“组件”在何处以及如何进入路径。这是某些规范的一部分吗?
Triynko 2014年

46

有人问有关用代码执行此操作的问题,但没有得到答案。

经过数小时的搜索,我发现了一个非常简单的方法,没有找到任何示例,因此在这里分享了我的适用于图像的方法。(我的是一个.gif)

摘要:

它返回ImageSource“目标”似乎喜欢的BitmapFrame。

采用:

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

方法:

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

学到:

根据我的经验,打包字符串不是问题,请检查您的流,尤其是如果第一次读取它已将指针设置为文件末尾,并且您需要在重新读取之前将其重置为零。

我希望这可以节省您很多时间,希望这件作品对我有帮助!


44

在代码中将资源加载到正在执行的程序集中,其中我的图像Freq.png位于该文件夹中,Icons并且定义为Resource

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

我还做了一个功能:

/// <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)); 
}

用法(假设您将函数放在ResourceHelper类中):

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

注意:请参阅WPF中的MSDN Pack URI
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml


新的Uri引发无效的URI:指定了无效的端口。
史蒂夫

你有冒犯的uri吗?
埃里克·厄勒

1
除了您的uri在运行WPF的Winform内运行之外,其他都与您相同。当我调用新的Uri时,“ pack”模式尚未注册。
史蒂夫,

1
糟糕...它可能已撤退到Winform托管WPF。对不起。我不会尝试修复它,因为我认为它不是很常见的用法。祝好运!
埃里克·厄勒

就我而言,使用new Uri(@"pack://application:,,,/" + pathInApplication)技巧也可以。
亚当·卡维特·布尔

40

是的,这是正确的方法。

您可以仅使用路径在资源文件中使用图像:

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

您必须将图像文件的构建操作设置为“资源”。


1
谢谢你 有没有一种方法可以对ImageSource做类似的事情,本质上是将图像一次加载到资源字典中。我担心这种方法会在内存中多次加载图像数据。
Drew Noakes

2
当您需要重构代码时,这将是一团糟。如果您的xaml文档恰巧更改了名称空间,则必须手动更改所有图像引用。Drew Noakes描述的方法更加平滑和可维护。
卡巴斯尔·霍尔顿


5
  1. Visual Studio 2010专业版SP1。
  2. .NET Framework 4客户端配置文件。
  3. PNG图像作为项目属性的资源添加。
  4. 资源文件夹中的新文件会自动创建。
  5. 将操作设置为资源。

这为我工作:

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

3

如果您正在使用Blend,要使其变得更加容易并且在获取Source属性的正确路径时没有任何麻烦,只需将图像从“项目”面板拖放到设计器上即可。


3

是的,这是正确的方法。您可以使用以下路径在资源文件中使用图像:

<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>

-5

以下工作和要设置的图像是属性中的资源:

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

5
没有冒犯,但这闻起来像是不好的做法。
ShloEmi 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.