在代码中设置WPF图像源


325

我正在尝试在代码中设置WPF图像的源。图像作为资源嵌入到项目中。通过查看示例,我得出了以下代码。由于某种原因,它不起作用-无法显示图像。

通过调试,我可以看到流包含图像数据。那怎么了

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;

图标定义如下: <Image x:Name="_icon" Width="16" Height="16" />


如果映像在本地驱动器上,<Image Source="some_fully_qualified_path">则XAML永远不会失败。
Laurie Stearn

@LaurieStearn的要点是我们不知道路径,需要代码才能确定它。作为Windows GUI编程的新手,我必须承认WinForms似乎比这种XAML废话更具吸引力。
Alex Jansen

Answers:


415

在遇到与您相同的问题并进行了一些阅读之后,我发现了解决方案-Pack URIs

我在代码中做了以下工作:

Image finalImage = new Image();
finalImage.Width = 80;
...
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png");
logo.EndInit();
...
finalImage.Source = logo;

或更短一些,通过使用另一个BitmapImage构造函数:

finalImage.Source = new BitmapImage(
    new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png"));

URI分为以下部分:

  • 权威: application:///
  • 路径:编译为引用程序集的资源文件的名称。路径必须符合以下格式:AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName:所引用程序集的简称。
    • ; Version [可选]:包含资源文件的引用程序集的版本。当加载两个或多个具有相同短名称的引用程序集时,将使用此方法。
    • ; PublicKey [可选]:用于对引用的程序集进行签名的公共密钥。当加载两个或多个具有相同短名称的引用程序集时,将使用此方法。
    • ; component:指定要引用的程序集是从本地程序集引用的。
    • / Path:资源文件的名称,包括其路径,相对于所引用程序集的项目文件夹的根目录。

之后的三个斜杠application:必须用逗号替换:

注意:包URI的授权组件是指向包的嵌入式URI,必须符合RFC2396。此外,“ /”字符必须替换为“,”字符和保留字符(例如“%”)和“?” 必须逃脱。有关详细信息,请参见OPC。

当然,请确保将图像上的构建操作设置为Resource


是的,这是经过反复试验后发现的解决方案。感谢您的详尽解释。答案已接受!
Torbjørn

我不知道为什么这需要,虽然,为什么其他的答案没有工作对我来说...
Torbjørn

这个问题和其他问题中的其他答案对我也不起作用。这是完美的作品。谢谢。
托马斯·

9
好的,但是XAML解析器没有用于将简单路径字符串转换为ImageSource的某些方法或类吗?我们不能只使用它吗?
2011年

1
我经常看到此代码段复制到其他帖子中,人们通常会忽略该代码段​​的存在BitmapImage(Uri),这有助于避免调用BeginInit和EndInit的需要。我已经在这里添加了。
Clemens

175
var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);

这将在名为“ WpfApplication1”的程序集中将名为“ Untitled.png”的图像加载到名为“ Images”的文件夹中,并将其“ Build Action”设置为“ Resource”。


16
感谢那。一个让我不喜欢wpf的问题,必须将图像标记为资源才能正常工作。
2009年

4
这个解决方案给了我一个例外,所以我尝试了Jared Harley的解决方案,它起作用了……
Sangram Nandkhile 2011年

2
最重要的是“ UriKind.RelativeOrAbsolute”-其他示例始终引发异常
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);足够了
Hamzeh Soboh

...而且容易得多。感谢Hamzeh
pStan

74

这少了一些代码,可以在一行中完成。

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;

8
利用.NET自己的实现,这绝对是最好的答案
joshcomley 2014年

如果我们需要设置图像的高度和宽度,即icon.png怎么办?因为通过使用_image.height和_image.width,它设置图像窗口而不是实际图像,即icon.png。
secretgenes '16

41

很容易:

若要动态设置菜单项的图像,请仅执行以下操作:

MyMenuItem.ImageSource = 
    new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));

...而“ icon.ico”可以放置在任何地方(当前位于'Resources'目录中),并且必须作为Resource链接起来...


2
更短=更好。我不得不将其设置为@“ / folder / image.png”,但随后工作正常。谢谢!
gjvdkamp 2011年

3
当我分配图像源时,它只是显示空白:(
HaloMediaz '16

@HaloMediaz路径可能是错误的....例如,您有资源,但您可以将其写为资源
Rouzbeh Zarandi,

这对我有用,并且比其他答案中的绝对URI更直接。
Psiloc

16

您也可以减少到一行。这是我用于为主窗口设置图标的代码。假定.ico文件已标记为“内容”,并且已复制到输出目录。

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));

16

最简单的方法:

var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);

15

你有没有尝试过:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;

13

这是我的方式:

internal static class ResourceAccessor
{
    public static Uri Get(string resourcePath)
    {
        var uri = string.Format(
            "pack://application:,,,/{0};component/{1}"
            , Assembly.GetExecutingAssembly().GetName().Name
            , resourcePath
        );

        return new Uri(uri);
    }
}

用法:

new BitmapImage(ResourceAccessor.Get("Images/1.png"))

8

这是一个动态设置映像路径的示例(映像位于光盘上某处,而不是作为资源构建):

if (File.Exists(imagePath))
{
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
}

关于图标的思考...

首先考虑一下,您会认为Icon属性只能包含图像。但是它实际上可以包含任何东西!当我以编程方式尝试将Image属性直接设置为带有图像路径的字符串时,偶然发现了这一点。结果是它没有显示图像,而是路径的实际文本!

这导致不必为图标制作图像,而是使用带有符号字体的文本来显示简单的“图标”。下面的示例使用Wingdings字体,其中包含一个“软盘”符号。此符号实际上是字符<,在XAML中具有特殊含义,因此我们必须改用编码版本&lt;。这就像一个梦想!下面在菜单项上将软盘符号显示为图标:

<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
  <MenuItem.Icon>
    <Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings">&lt;</Label>
  </MenuItem.Icon>
</MenuItem>

问题:“ 图像作为资源嵌入到项目中 ”,回答:“ 这是[图像的示例]位于光盘上的某个位置,而不是作为资源构建 ”。
分钟

7

如果您的图像存储在ResourceDictionary中,则只需一行代码即可完成:

MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;

6

还有一种更简单的方法。如果将图像作为XAML中的资源加载,并且该代码位于该XAML内容的代码后面:

Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);

4

将框架放入VisualBrush中:

VisualBrush brush = new VisualBrush { TileMode = TileMode.None };

brush.Visual = frame;

brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;

将VisualBrush放在GeometryDrawing中

GeometryDrawing drawing = new GeometryDrawing();

drawing.Brush = brush;

// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;

现在将GeometryDrawing放在DrawingImage中:

new DrawingImage(drawing);

将其放在您的图像来源上,瞧瞧!

不过,您可以轻松得多:

<Image>
    <Image.Source>
        <BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
    </Image.Source>
</Image>

并在代码中:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };

大声笑!为什么可以很容易当你第一次能让人很难:)我来试试你的简单的解决方案之前,我接受,但...
Torbjørn

实际上,这根本没有帮助我。也许我笨:(没有时间来仔细看看现在(宠物项目)希望更多的答案,当我回去吧:)
Torbjørn

3

还有一种更简单的方法。如果图像在XAML中作为资源加载,并且该代码位于该XAML的代码背后:

这是XAML文件的资源字典-您关心的唯一一行是带有键“ PosterBrush”的ImageBrush-其余代码仅用于显示上下文

<UserControl.Resources>
        <ResourceDictionary>
            <ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>

        </ResourceDictionary>
    </UserControl.Resources>

现在,在后面的代码中,您可以执行此操作

ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];

2

如何从资源图标和图像中嵌入图像(Arcturus的更正版本):

假设您要添加带有图像的按钮。你该怎么办?

  1. 添加到项目文件夹图标,然后在此处放置图片ClickMe.png
  2. 在“ ClickMe.png”的属性中,将“ BuildAction”设置为“ Resource”
  3. 假设您编译的程序集名称为“ Company.ProductAssembly.dll”。
  4. 现在是时候将图像加载到XAML中了

    <Button Width="200" Height="70">
      <Button.Content>
        <StackPanel>
          <Image Width="20" Height="20">
            <Image.Source>
              <BitmapImage UriSource="/Company.ProductAssembly;component/Icons/ClickMe.png"></BitmapImage>
              </Image.Source>
          </Image>
          <TextBlock HorizontalAlignment="Center">Click me!</TextBlock>
        </StackPanel>
      </Button.Content>
    </Button>

做完了


2

我是WPF的新手,但不是.NET。

我花了五个小时试图将PNG文件添加到.NET 3.5(Visual Studio 2010)中的“ WPF自定义控件库项目”中,并将其设置为图像继承控件的背景。

没有任何与URI相关的工作。我无法想象为什么没有方法可以通过IntelliSense从资源文件获取URI,也许是这样的:

Properties.Resources.ResourceManager.GetURI("my_image");

我已经尝试了很多URI,并使用了ResourceManager和Assembly的GetManifest方法,但是都存在异常或NULL值。

在这里,我放入了对我有用的代码:

// Convert the image in resources to a Stream
Stream ms = new MemoryStream()
Properties.Resources.MyImage.Save(ms, ImageFormat.Png);

// Create a BitmapImage with the stream.
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();

// Set as source
Source = bitmap;

3
我认为问题在于WPF不“喜欢”将资源放入resx文件的传统方法。相反,您应该将图像直接添加到项目中,并将其Build Action属性设置为Resource。我不知道这两种方法之间的区别(就物理文件格式而言)是什么。
Qwertie 2011年

1
确保构建操作符合要求
Jerry Nixon

1

如果您已经有一个流并且知道格式,则可以使用以下格式:

static ImageSource PngStreamToImageSource (Stream pngStream) {
    var decoder = new PngBitmapDecoder(pngStream,
        BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    return decoder.Frames[0];
}

1

你只是错过了一点。

要从任何程序集中获取嵌入式资源,您必须使用我在这里提到的文件名来提及程序集名称:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream(asm.GetName().Name + "." + "Desert.jpg");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
image1.Source = bitmap;

WPF中似乎不存在BeginInit()。
Myosotis

这是下面的链接可检查 msdn.microsoft.com/en-us/library/...
maulik kansara
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.