C# - 从不同程序集加载图像
C# - 从不同程序集加载图像
我有一张图片在不同的程序集中:
- (.NET Standard 1.4) ResourcesAssembly/Common/Images/CompanyLogo.png - 强制要求
- Build Action: Content - 强制要求
- Copy to output directory: Copy if newer (我在编译后检查过 - 所需的图片存在于输出目录中,即我的exe所在的位置 - 例如,Debug/Common/Images/CompanyLogo.png。所以从那里获取应该没有问题。)
我想把它粘贴到我的应用程序的程序集(WPF)中的一个窗口里。我尝试了两种变体。
1.
界面中的图像在运行时可见。但是VS的XAML设计器在设计时不显示图像,并显示错误信息:
找不到路径的一部分 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\Common\Images\CompanyLogo.png'。
2.
图像在运行时不可见,但在设计时一切正常。
Visual Studio 2017 Community Edition 15.4.4。
所以第一种变体对我来说似乎合适,但是那个奇怪的错误 - 为什么它尝试在Visual Studio文件夹中找到图像呢?"siteoforigin"选项与应用程序exe相关,而不是Visual Studio exe,对吗?
更新
尝试了第二种变体,以"嵌入资源"的构建操作(ResourcesAssembly是一个.NET Standard 1.4项目)。甚至清理并重新构建了解决方案。结果与第二种变体相同:图像在运行时不可见,但在设计时可见。
问题出现的原因是在WPF中加载不同程序集中的图像时,application
在设计时正常工作,但在运行时不起作用,而siteoforigin
则相反。
解决方法是在控件的Source
属性设置时进行拦截。一种方法是使用继承。下面是一个针对ResourceDictionary的示例实现:
////// A modified type of public class SiteOfOriginResourceDictionary : ResourceDictionary { private const string SiteOfOriginPrefix = "pack://siteoforigin:,,,"; private const string ApplicationPrefix = "pack://application:,,,"; private const string UseRedirectSource = "Please use RedirectSource instead of Source"; private string _originalUri; ///that translates "Resource" pack URIs to "Site of Origin" /// pack URIs when in runtime. /// /// i.e. This allows you to declare pack URIs as "pack://application:,,,", which will be resolved /// as such in design mode while at runtime, actually using "pack://siteoforigin:,,,". /// /// Gets or sets the design time source. /// public string RedirectSource { get => _originalUri; set { this._originalUri = value; bool isInDesignMode = (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue; if (!isInDesignMode) { if (value.Contains(ApplicationPrefix)) value = value.Replace(ApplicationPrefix, SiteOfOriginPrefix); } base.Source = new Uri(value); } } ////// Please use public new Uri Source { get => throw new Exception(UseRedirectSource); set => throw new Exception(UseRedirectSource); } }instead. ///
使用示例:
这种解决方法在实践中对我起到了作用,并且我经常使用这段代码。我相信你也可以在Image
和其他WPF组件中使用相同的方法。
另外,我不知道为什么在将资源的构建操作设置为Content
时,使用application
在设计时起作用。根据文档,这个URI应该在资源"被编译到引用的程序集中"时使用,但是对我来说,这个方法可以正常工作。
这是我在StackOverflow上的第一篇帖子,我是一个业余爱好者,请多多指教 。
在使用Visual Studio的XAML设计器时,执行的程序集是XDesProc.exe(位于指定目录C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE)。这就是为什么图像搜索路径是...\IDE\Common\Images\CompanyLogo.png的原因。
如果你想同时满足两个要求(第一,图像在外部资源程序集中,第二,图像的构建操作设置为'Content'),那么可能没有办法同时在WPF设计器和应用程序运行时正确显示图像。至少我无法找到解决方案。
siteorigin
权限在打包URI中不适用,因为图像应该在不同的应用程序中加载,这些应用程序具有不同的执行目录。
application
权限在打包URI中不适用,因为它仅适用于编译到程序集中(本地或引用的)的资源文件。这实际上是为什么你在第二个变体中在运行时看不到图像的原因。
所以,如果第一个变体适合你,那么好吧,这是你在不违反你声明的要求的情况下能得到的最好的解决方案。最接近的解决方案是将图像的Build Action
设置为Resource
,并在第二个源路径中使用application
权限,这样可以在设计器和运行时中正确显示图像。
更新:
“Resource”构建操作对于.Net Standard类库不可用。我没有找到任何关于是否将来会支持它的信息。目前,如果你的ResourcesAssembly
必须针对.Net Standard,请使用你在问题中描述的第一个变体。
将构建操作设置为资源将使图像文件成为实际的“程序集资源”,最适合关于从程序集中加载图像的问题,或者关于在不同的程序集中的图像的问题。
关于你的问题,我尝试按照你的建议进行操作,但在XAML设计器和WPF应用程序的运行时中仍然无法看到可见的图像。虽然对我来说,第一个变体现在是最合适的,但是我很想知道问题出在哪里。
在你的问题中,评论者正确地指出,选择Resource而不是Embedded Resource。
在.NET Standard 1.4项目类型中没有“Resource”选项,只有“Embedded resource”,我认为在普通的.NET项目类型中,Embedded resource相当于Resource。我说的对吗?
我指定了我的问题,资源库的类型是.NET Standard 1.4。
通过你的解释,我完全明白你的答案了。我困惑于“但是当你使用VS的XAML设计器时,执行的程序集是XDesProc.exe”,我经常在我的设计器属性对我的点击或输入不响应时终止这个进程。现在,我明白了siteoforigin的含义。