Wpf 将URI打包到嵌入在resx文件中的图像
如何为资源文件中的映像构造包URI 我有一个名为MyAssembly.Resources.dll的程序集,它有一个名为Images的文件夹,然后在其中有一个名为Assets.resx的资源文件。此资源文件包含我的图像(称为MyImage.png)。我的代码行是:Wpf 将URI打包到嵌入在resx文件中的图像,wpf,image,internationalization,resources,uri,Wpf,Image,Internationalization,Resources,Uri,如何为资源文件中的映像构造包URI 我有一个名为MyAssembly.Resources.dll的程序集,它有一个名为Images的文件夹,然后在其中有一个名为Assets.resx的资源文件。此资源文件包含我的图像(称为MyImage.png)。我的代码行是: uri = new Uri("pack://application:,,,/MyAssembly.Resources,Culture=neutral,PublicKeyToken=null;component/Images/Assets
uri = new Uri("pack://application:,,,/MyAssembly.Resources,Culture=neutral,PublicKeyToken=null;component/Images/Assets/MyImage.png");
然而,当我试图将这个URI提供给一个新的URI的构造函数时,我得到了一条消息
找不到资源“images/assets/myimage.png”
请注意,我在同一程序集中有其他松散映像,我可以使用包URI很好地检索这些映像,这些映像的构建操作设置为Resource,但它们没有嵌入到resx文件中。我应该在路径中包含resx文件的名称吗
(我希望在resx文件中嵌入图像,以便利用UI区域性设置检索正确的图像(图像包含文本))。有两种方法可以在程序集中“嵌入”资源。Windows窗体使用嵌入式资源
生成操作。
WPF希望程序集中包含的资源用Resource
Build操作标记
在VisualStudio中使用Resx编辑器添加图像时,它会将其标记为嵌入式资源。此外,它还将其存储为typeSystem.Drawing.Bitmap
。WPF需要一个System.Windows.Media.ImageSource
类型
如果您有一个disembler(比如ILSpy),您可以查看在文件上设置不同构建操作的影响
示例ImagesLib项目
下面是一个项目的截图,其中有两张图片。从名称中可以明显看出,cat_embedded.jpg
正在使用embedded Resource
构建操作,而cat_Resource.jpg
正在使用Resource
构建操作
这就是他们在ILSpy中的样子
查看cat_resource.jpg文件在ImageLib.g.resources部分中的位置?这就是WPF寻找资源的地方。文件路径是资源名称的一部分(images/cat\u resource.jpg
)。因此,当您使用以下路径时:
var uri = new Uri("pack://application:,,,/ImageLib;component/Images/cat_resource.jpg");
在单词之后指定匹配路径;组件
另一个jpg文件位于程序集中的不同位置,并在名称中使用句点(ImageLib.Images.cat_embedded.jpg
)
您可以尝试对该字符串进行多种排列,以尝试获取cat_embedded.jpg图像,但WPF找不到它
RESX编辑器
这里是另一个项目,它有两个图像,一个标记为资源,另一个由resx编辑器添加
这是分解后的屏幕截图
如您所见,resx映像使用的URI位置与前面的嵌入映像示例相同。
在您的情况下,似乎无法使用packuri从resx文件获取图像
本地化
从您在问题中所说的,您试图实现的是图像的本地化,对吗
你看过这篇MSDN文章了吗
我认为不可能使用“打包”协议方案。该协议与规范化的开放式封装约定规范(针对指针)相关。因此,包uri指向应用程序包的资源(或OPC术语中的部分),而不是.NET嵌入式资源 但是,您可以定义自己的方案,例如“resx”,并在WPF组件URI中使用它。可以使用定义这种用法的新Uri方案 下面是一个基于名为“WpfApplication1”的小型Wpf应用程序项目的示例。此应用程序定义了一个Resource1.resx文件(可能还有其他本地化的相应Resource1文件,例如法语的Resource1.fr-fr.resx)。这些ResX文件中的每个文件都定义了一个名为“img”的图像资源(请注意,此名称与资源所基于的图像文件名不同) 以下是MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Image Source="resx:///WpfApplication1.Resource1/img" />
</Window>
程序集名称是可选的,所以
resx:///resource set name/resource name
也有效,并指向主程序集中的资源(我的示例使用此选项)
这是支持它的代码,在App.xaml.cs或其他地方,您需要注册新方案:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ResXWebRequestFactory.Register();
base.OnStartup(e);
}
}
以及计划的实施情况:
public sealed class ResXWebRequestFactory : IWebRequestCreate
{
public const string Scheme = "resx";
private static ResXWebRequestFactory _factory = new ResXWebRequestFactory();
private ResXWebRequestFactory()
{
}
// call this before anything else
public static void Register()
{
WebRequest.RegisterPrefix(Scheme, _factory);
}
WebRequest IWebRequestCreate.Create(Uri uri)
{
return new ResXWebRequest(uri);
}
private class ResXWebRequest : WebRequest
{
public ResXWebRequest(Uri uri)
{
Uri = uri;
}
public Uri Uri { get; set; }
public override WebResponse GetResponse()
{
return new ResXWebResponse(Uri);
}
}
private class ResXWebResponse : WebResponse
{
public ResXWebResponse(Uri uri)
{
Uri = uri;
}
public Uri Uri { get; set; }
public override Stream GetResponseStream()
{
Assembly asm;
if (string.IsNullOrEmpty(Uri.Host))
{
asm = Assembly.GetEntryAssembly();
}
else
{
asm = Assembly.Load(Uri.Host);
}
int filePos = Uri.LocalPath.LastIndexOf('/');
string baseName = Uri.LocalPath.Substring(1, filePos - 1);
string name = Uri.LocalPath.Substring(filePos + 1);
ResourceManager rm = new ResourceManager(baseName, asm);
object obj = rm.GetObject(name);
Stream stream = obj as Stream;
if (stream != null)
return stream;
Bitmap bmp = obj as Bitmap; // System.Drawing.Bitmap
if (bmp != null)
{
stream = new MemoryStream();
bmp.Save(stream, bmp.RawFormat);
bmp.Dispose();
stream.Position = 0;
return stream;
}
// TODO: add other formats
return null;
}
}
}
我在这篇博文中描述了在WPF中使用resx图像的组件:。您将在下找到更多关于在WPF中使用resx资源的帖子
在这些文章中,我不使用包URI,而是使用标记扩展。正如Walt正确地指出的,从resx文件中得到的是一个
系统.Drawing.Bitmap
。因此,需要将其转换为System.Windows.Media.ImageSource
或子类型
我不确定这是否属于您的时间浪费,因为它没有使用URI,但下面是我如何从另一个库中的resx文件获取图像。我之所以使用,是因为resx设计器文件仅公开内部构造函数(即使该类是公共的),然后定义将提供ImageSource的ValueConverter
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:resx="clr-namespace:MyAssembly.Resources;assembly=MyAssembly.Resources"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<resx:AssetsProxy x:Key="Assets" />
<resx:BitmapToImageSourceConverter x:Key="BitmapConverter" />
</Window.Resources>
<Image Source="{Binding myimage, Source={StaticResource Assets}, Converter={StaticResource BitmapConverter}}" />
</Window>
位图到图像源转换:
using System;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace MyAssembly.Resources
{
/// <summary>
/// Converts a BitmapImage, as provided by a resx resource, into an ImageSource/BitmapImage
/// </summary>
public class BitmapToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
BitmapImage bitmapImage = null;
if (value is System.Drawing.Image)
{
bitmapImage = ((System.Drawing.Image)value).ToBitmapImage();
}
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public static class BitmapExtensions
{
/// <summary>
/// Converts the System.Drawing.Image to a System.Windows.Media.Imaging.BitmapImage
/// </summary>
public static BitmapImage ToBitmapImage(this System.Drawing.Image bitmap)
{
BitmapImage bitmapImage = null;
if (bitmap != null)
{
using (MemoryStream memory = new MemoryStream())
{
bitmapImage = new BitmapImage();
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
}
return bitmapImage;
}
}
}
使用系统;
使用系统、绘图、成像;
利用制度全球化;
使用System.IO;
使用System.Windows.Data;
使用System.Windows.Media.Imaging;
名称空间MyAssembly.Resources
{
///
///将resx资源提供的BitmapImage转换为ImageSource/BitmapImage
///
公共类BitmapToImageSourceConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
BitmapImage BitmapImage=null;
if(值为System.Drawing.Image)
{
bitmapImage=((System.Drawing.Image)值).ToBitmapImage();
}
返回位图图像;
}
公共对象转换回(对象值、类型targetType、对象参数、CultureInfo区域性)
{
抛出新的NotImplementedException();
}
namespace MyAssembly.Resources
{
public class AssetsProxy : Images.Assets
{
public AssetsProxy() : base() { }
}
}
using System;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace MyAssembly.Resources
{
/// <summary>
/// Converts a BitmapImage, as provided by a resx resource, into an ImageSource/BitmapImage
/// </summary>
public class BitmapToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
BitmapImage bitmapImage = null;
if (value is System.Drawing.Image)
{
bitmapImage = ((System.Drawing.Image)value).ToBitmapImage();
}
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public static class BitmapExtensions
{
/// <summary>
/// Converts the System.Drawing.Image to a System.Windows.Media.Imaging.BitmapImage
/// </summary>
public static BitmapImage ToBitmapImage(this System.Drawing.Image bitmap)
{
BitmapImage bitmapImage = null;
if (bitmap != null)
{
using (MemoryStream memory = new MemoryStream())
{
bitmapImage = new BitmapImage();
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
}
return bitmapImage;
}
}
}