" /> "> " />
我正在尝试在代码中设置 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">
永远不会失败。
在遇到与您相同的问题并阅读后,我发现了解决方案 - 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 分为几部分:
权限:应用程序:///
路径:编译成引用程序集的资源文件的名称。路径必须符合以下格式: AssemblyShortName[;Version][;PublicKey];component/Path AssemblyShortName:被引用程序集的短名称。 ;Version [可选]:包含资源文件的引用程序集的版本。这在加载两个或多个具有相同短名称的引用程序集时使用。 ;PublicKey [可选]:用于签署引用程序集的公钥。这在加载两个或多个具有相同短名称的引用程序集时使用。 ;component:指定被引用的程序集是从本地程序集引用的。 /Path:资源文件的名称,包括其路径,相对于所引用程序集的项目文件夹的根目录。
AssemblyShortName:被引用程序集的短名称。
;Version [可选]:包含资源文件的引用程序集的版本。这在加载两个或多个具有相同短名称的引用程序集时使用。
;PublicKey [可选]:用于签署引用程序集的公钥。这在加载两个或多个具有相同短名称的引用程序集时使用。
;component:指定被引用的程序集是从本地程序集引用的。
/Path:资源文件的名称,包括其路径,相对于所引用程序集的项目文件夹的根目录。
application:
之后的三个斜杠必须用逗号替换:
注意:包 URI 的授权组件是一个嵌入式 URI,它指向一个包,并且必须符合 RFC 2396。此外,“/”字符必须替换为“,”字符和保留字符,例如“%”和 ”?”必须逃脱。有关详细信息,请参阅 OPC。
当然,请确保将映像上的构建操作设置为 Resource
。
var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);
这将在名为“Images”的文件夹中加载名为“Untitled.png”的图像,其“Build Action”在名为“WpfApplication1”的程序集中设置为“Resource”。
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);
就足够了
pack://application:,,,
附加到 Uri 可以。
这是更少的代码,可以在一行中完成。
string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;
很容易:
要动态设置菜单项的图像,只需执行以下操作:
MyMenuItem.ImageSource =
new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));
...而“icon.ico”可以位于任何地方(目前它位于“资源”目录中)并且必须作为资源链接...
最简单的方法:
var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);
这是我的方式:
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"))
您也可以将其减少为一行。这是我用来设置主窗口图标的代码。它假定 .ico 文件被标记为内容并被复制到输出目录。
this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));
你有没有尝试过:
Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;
如果您的图像存储在 ResourceDictionary 中,则只需一行代码即可:
MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;
这是一个动态设置图像路径的示例(图像位于磁盘上的某个位置,而不是作为资源构建):
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"><</Label>
</MenuItem.Icon>
</MenuItem>
还有一种更简单的方法。如果图像作为 XAML 中的资源加载,并且相关代码是该 XAML 内容的代码隐藏:
Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);
将框架放入 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" };
还有一种更简单的方法。如果图像作为 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"];
如何从嵌入的资源图标和图像中加载图像(Arcturus 的更正版本):
假设您要添加一个带有图像的按钮。你该怎么办?
添加到项目文件夹图标并将图像 ClickMe.png 放在这里 在“ClickMe.png”的属性中,将“BuildAction”设置为“Resource”假设您编译的程序集名称是“Company.ProductAssembly.dll”。现在是时候在 XAML 中加载我们的图像
完毕。
我是 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;
你只是错过了一点。
要从任何程序集中获取嵌入式资源,您必须在文件名中提及程序集名称,正如我在这里提到的:
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;
如果你已经有一个流并且知道格式,你可以使用这样的东西:
static ImageSource PngStreamToImageSource (Stream pngStream) {
var decoder = new PngBitmapDecoder(pngStream,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
return decoder.Frames[0];
}
如果您想在可执行文件旁边找到它(相对于可执行文件)
img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + @"\Images\image.jpg", UriKind.Absolute));
强制选择 UriKind 将是正确的:
Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));
UriKind 选项:
UriKind.Relative // relative path
UriKind.Absolute // exactly path
不定期副业成功案例分享
BitmapImage(Uri)
构造函数的存在,这有助于避免调用 BeginInit 和 EndInit。我在这里添加了它。