C# - 从不同的程序集

时间:2018-02-11 11:21:21

标签: c# .net wpf resources .net-standard-1.4

我有不同程序集的图像:

  • (。NET Standard 1.4)ResourcesAssembly / Common / Images / CompanyLogo.png - 强制性要求
  • 构建操作:内容 - 强制要求
  • 复制到输出目录:如果更新则复制(我在编译后检查 - 所需的图像显示在我的exe所在的输出目录中 - 例如,Debug / Common / Images / CompanyLogo.png。所以应该没有从那里得到它的问题。)

我想将其粘贴到窗口内的应用程序程序集(WPF)中。我尝试了两种变种。

1

<Image Source="pack://siteoforigin:,,,/Common/Images/CompanyLogo.png" />

界面中的图像在运行时可见。但VS的XAML设计师在设计时并没有显示图像,并说这是一个错误:

  

无法找到路径的一部分&#39; C:\ Program Files(x86)\ Microsoft   视觉   工作室\ 2017 \社区\ Common7 \ IDE \共同\ IMAGES \ CompanyLogo.png&#39;

2

<Image Source="pack://application:,,,/ResourcesAssembly;component/Common/Images/CompanyLogo.png" />

图像在运行时不可见,但在设计时一切正常。

Visual Studio 2017社区版15.4.4。

所以第一个变种似乎适合我,但是这个奇怪的错误 - 为什么它试图在Visual Studio文件夹中找到图像? &#34; siteoforigin&#34;选项与应用程序exe相关,而不是与Visual Studio exe相关,不是吗?

更新

尝试使用构建操作的第二个变体作为&#34;嵌入式资源&#34; (ResourcesAssembly是.NET Standard 1.4项目)。甚至清理并重建了解决方案。结果与第二个变体中的结果相同:图像在运行时不可见,但在设计时它是可见的。

2 个答案:

答案 0 :(得分:3)

  

&#34; siteoforigin&#34;选项涉及应用程序exe,而不是   Visual Studio exe,不是吗?

确实,siteoforigin指向执行程序集目录。但是当你使用VS的XAML设计器时,从你指定的目录(C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE)执行程序集是... XDesProc.exe。这就是图片搜索路径为...\IDE\Common\Images\CompanyLogo.png的原因。

您可以问 - &#34;有没有办法在WPF设计器和应用程序运行时中正确地显示图像?&#34;好吧,如果你想保持两个要求(第一个 - 外部资源装配中的图像,第二个 - 图像集的构建操作设置为&#39;内容&#39;),那么可能没有。至少我无法找到解决方案。

包URI中具有siteorigin权限的选项不合适,因为图像应该加载到具有不同执行目录的不同应用程序中(参见上文)。

包URI中具有application权限的选项不适用,因为它仅适用于编译为程序集(本地或引用)的资源文件。这实际上是你在第二个版本中没有在运行时看到图像的原因。

因此,如果第一个版本适合您,那么确定,它是您可以拥有的最好的,同时不违反您声明的要求。允许在Designer和运行时正确查看图像的最近解决方案是将Build Action设置为Resource以获取图像,并使用具有application权限的第二个源路径。 / p>

<强>更新

&#34;资源&#34;构建操作不适用于.Net标准类库。我还没有找到任何信息是否会得到支持。目前,如果您的ResourcesAssembly必须以.Net标准为目标,那么您最好的选择是使用您在问题中描述的第一个变体。

答案 1 :(得分:0)

我对WPF还是很陌生,最近在业余时间从事一个业余项目时,遇到了一个非常相似的问题,受了类似的约束。

尽管如此,正如您已经认识到的那样,application在设计时可以正常运行,而在运行时则不能,而siteoforigin则相反。因此,解决此问题的一种合理方法是简单地同时使用siteoforigin和运行时的application

为此,您只需要截取控件的Source属性的设置即可。一种方法是使用继承


以下是为 ResourceDictionary 执行此操作的示例:

实施

/// <summary>
/// A modified type of <see cref="ResourceDictionary"/> 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:,,,".
/// </summary>
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;

    /// <summary>
    /// Gets or sets the design time source.
    /// </summary>
    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);
        }
    }

    /// <summary>
    /// Please use <see cref="RedirectSource"/> instead.
    /// </summary>
    public new Uri Source
    {
        get => throw new Exception(UseRedirectSource);
        set => throw new Exception(UseRedirectSource);
    }
}

用法示例

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <SiteOfOriginResourceDictionary RedirectSource="pack://application:,,,/Theme/Default/Root.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</ResourceDictionary.MergedDictionaries>

在实践中,此解决方案对我有用,并且我积极使用此代码。我敢肯定,您可以使用Image和/或其他WPF组件执行相同的操作。

也就是说,就我而言,我只需要在ResourceDictionary上提供支持。在您的情况下,此解决方案不是最佳选择,因为您可能(最终)可能需要对以后的多个控件执行此操作。

这样,我将提出一个可能的解决方案,以进一步研究Attached Properties的使用,并创建一个附加属性来设置控件的Source,在application之间切换设计时间和siteoforigin在运行时。

相反,它可以在多个控件中重复使用,而不必每次都为每个新控件/类继承。


在相关说明中,我不能说我知道为什么将资源的构建操作设置为application时在设计器中使用Content的原因。根据文档,当资源“被编译为引用的程序集” Source)时,将使用此URI,但是仍然对我有用。

这是我在StackOverflow上的第一篇文章,并且是我的爱好者,所以请放轻松。