在代码中设置 WPF 图像源

Posted

技术标签:

【中文标题】在代码中设置 WPF 图像源【英文标题】:Setting WPF image source in code 【发布时间】:2010-09-25 21:19:06 【问题描述】:

我正在尝试在代码中设置 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" />

【问题讨论】:

如果图像在本地驱动器上,XAML 中的<Image Source="some_fully_qualified_path"> 永远不会失败。 @LaurieSearn 重点是我们不知道路径并且需要代码来确定它。作为 Windows GUI 编程的新手,我不得不承认 WinForms 似乎比这个 XAML 废话更有吸引力。 【参考方案1】:

在遇到与您相同的问题并阅读了一些内容后,我发现了解决方案 - 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:被引用程序集的短名称。 ;版本[可选]:包含资源文件的引用程序集的版本。这在加载两个或多个具有相同短名称的引用程序集时使用。 ;PublicKey [可选]:用于对引用程序集进行签名的公钥。这在加载两个或多个具有相同短名称的引用程序集时使用。 ;component:指定被引用的程序集是从本地程序集引用的。 /Path:资源文件的名称,包括其路径,相对于被引用程序集的项目文件夹的根目录。

application: 后面的三个斜杠必须用逗号代替:

注意:包 URI 的权限组件 是一个嵌入式 URI,它指向 包,并且必须符合 RFC 2396。 此外,“/”字符必须 替换为“,”字符, 和保留字符,例如“%” 和 ”?”必须逃脱。参见 OPC 了解详情。

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

【讨论】:

是的,这是我经过反复试验后找到的解决方案。感谢您的详尽解释。已接受答案! 我不知道为什么需要这样做,为什么其他答案对我不起作用...... 这个问题和其他问题中的其他答案对我也不起作用。这个完美无缺。谢谢。 好的,但是 XAML 解析器是否使用某些方法或类将简单路径字符串转换为 ImageSource?我们不能就用那个吗? 我经常看到这个sn-p被复制到其他帖子中,人们通常会忽略BitmapImage(Uri)构造函数的存在,这有助于避免调用BeginInit和EndInit的需要。我已经在这里添加了。【参考方案2】:
var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);

这将在名为“Images”的文件夹中加载名为“Untitled.png”的图像,其“构建操作”在名为“WpfApplication1”的程序集中设置为“资源”。

【讨论】:

谢谢。一个让我成为 wpf 菜鸟的问题,必须将图像标记为资源才能正常工作。 这个解决方案给了我一个例外,所以我尝试了 Jared Harley 的解决方案,它奏效了...... 最重要的是“UriKind.RelativeOrAbsolute”——其他例子总是抛出异常 var uriSource = new Uri("Images/Untitled.png", UriKind.Relative); 就足够了 这个解决方案对我不起作用,但是将 pack://application:,,, 附加到 Uri 中。【参考方案3】:

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

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

【讨论】:

这绝对是最好的答案,利用 .NETs 自己的实现 如果我们需要设置图片的高度和宽度,即icon.png怎么办?因为通过使用 _image.height 和 _image.width 它设置图像窗口而不是实际图像,即 icon.png。【参考方案4】:

很简单:

要动态设置菜单项的图像,只需执行以下操作:

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

...而“icon.ico”可以位于任何地方(目前它位于“资源”目录中)并且必须作为资源链接...

【讨论】:

更短 = 更好。我不得不将它设置为 @"/folder/image.png" 但是它工作正常。谢谢! 当我分配图像源时,它只是显示为空白:( @HaloMediaz 路径可能是错误的......例如,你有 Resources,但你可以写它 Resource 这对我有用,而且比其他答案中的绝对 URI 要简单得多。【参考方案5】:

最简单的方法:

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

【讨论】:

【参考方案6】:

这是我的方式:

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

【讨论】:

很好的解决方案。无需关心程序集名称即可轻松返回字符串并使用 Binding。【参考方案7】:

您也可以将其减少为一行。这是我用来设置主窗口图标的代码。它假定 .ico 文件被标记为 Content 并被复制到输出目录。

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

【讨论】:

【参考方案8】:

你试过了吗:

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

【讨论】:

【参考方案9】:

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

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

【讨论】:

【参考方案10】:

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

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 font。这个符号实际上是字符<,在XAML中有特殊含义,所以我们必须使用编码版本<来代替。这就像做梦一样!下面将软盘符号显示为菜单项上的图标:

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

【讨论】:

问题:“图像作为资源嵌入到项目中”,回答:“这是一个示例 [for an image],位于磁盘上的某个位置,而不是而不是构建为资源“。【参考方案11】:

还有一种更简单的方法。如果图像作为 XAML 中的资源加载,并且相关代码是该 XAML 内容的代码隐藏:

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

【讨论】:

【参考方案12】:

将框架放入 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" ;

【讨论】:

哈哈!为什么要先让它变得容易却变得容易:) 我会在接受之前尝试您的简单解决方案... 实际上这对我没有帮助。也许我很愚蠢:(现在没有时间更仔细地看(宠物项目)。当我回到它时想要更多答案:)【参考方案13】:

还有一种更简单的方法。如果图像作为 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"];

【讨论】:

【参考方案14】:

如何从嵌入的资源图标和图像中加载图像(Arcturus 的修正版):

假设您想添加一个带有图像的按钮。你应该怎么做?

    添加到项目文件夹图标并将图像ClickMe.png放在这里 在“ClickMe.png”的属性中,将“BuildAction”设置为“Resource” 假设您编译的程序集名称是“Company.ProductAssembly.dll”。

    现在是时候在 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>
    

完成。

【讨论】:

【参考方案15】:

我是 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;

【讨论】:

我认为问题在于 WPF 不“喜欢”将资源放入 resx 文件的传统方法。相反,您应该将图像直接添加到您的项目中并将其 Build Action 属性设置为 Resource。我不知道这两种方法有什么区别(就物理文件格式而言)。 确保构建操作是内容【参考方案16】:

如果你已经有一个流并且知道格式,你可以使用这样的东西:

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

【讨论】:

【参考方案17】:

你只是错过了一点。

要从任何程序集中获取嵌入式资源,您必须在此处提及程序集名称和文件名:

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;

【讨论】:

BeginInit() 在 WPF 中似乎不存在。 可以查看下面的链接msdn.microsoft.com/en-us/library/…【参考方案18】:

如果您想在可执行文件旁边找到它(相对于可执行文件)

img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + @"\Images\image.jpg", UriKind.Absolute));

【讨论】:

【参考方案19】:

强制选择 UriKind 将是正确的:

Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));

UriKind 选项:

UriKind.Relative // relative path
UriKind.Absolute // exactly path

【讨论】:

以上是关于在代码中设置 WPF 图像源的主要内容,如果未能解决你的问题,请参考以下文章

WPF 在代码中设置 MenuItem.Icon

TextBlock在wpf C#中的图像内的特定坐标中设置

使用 WPF、Caliburn 和 C# 从图像转换为图像源

如果在 Element 中设置,WPF 触发器将不会设置属性

Xamarin.Forms 在共享项目中设置图像源

WPF 在代码隐藏中设置 TextBox 属性