在代码中设置 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
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。这个符号实际上是字符&lt;
,在XAML中有特殊含义,所以我们必须使用编码版本&lt;
来代替。这就像做梦一样!下面将软盘符号显示为菜单项上的图标:
<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
<MenuItem.Icon>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings"><</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、Caliburn 和 C# 从图像转换为图像源