wpf - 将图标作为资源嵌入到 WPF 应用程序中

标签 wpf resources embedded-resource

我正在尝试将一个图标嵌入到我的 WPF 应用程序中,以便我可以使用以下代码将其拉出以用作 Windows 7 JumpList 中的图标:

newScene.IconResourcePath = System.Reflection.Assembly.GetEntryAssembly().Location;
newScene.IconResourceIndex = 0;

我已经使用以下方法让它工作了:http://dennisdel.com/?p=38

但是,这似乎不是最好的方法,似乎应该有一种更简单的方法将图标资源嵌入到我的应用程序中,同时仍然在应用程序属性中选中“ 图标和 list ”选项对于我的程序。

我尝试了很多方法,包括将图标构建操作设置为资源和嵌入资源,但是每次我在资源编辑器中打开我的 .exe 时,图标都不会出现。

有什么建议吗?

最佳答案

Visual Studio 没有提供从 MSBuild 任务执行 Win32 资源编译器的方法,也没有用于创建资源的嵌入式功能创建原始资源。因此,您的选择是:

  • 如链接文章中所述,“手动”创建 .res 文件,或
  • 添加构建任务,以便您可以从 .csproj
  • 调用 Win32 资源编译器

    首先,我将解释可以存在于 .exe 或 .dll 文件中的五种不同“资源”之间的区别,包括 JumpList 所需的“Win32 资源”。

    然后,我将解释如何构建一个自定义构建任务,该任务允许您在 C# 或 VB.NET 可执行文件中嵌入任意 Win32 资源。

    Win32 可执行文件中的五种资源

    .exe 或 .dll 文件中可以存在五种不同类型的“资源”:
  • Win32资源
  • NET 框架“嵌入式资源”
  • ResourceSet 中的 CLR 对象
  • XAML 资源
  • WPF 资源(ResourceDictionary 中的对象)

  • Win32资源

    原始资源类型是 Win32“资源”。这种资源在 .rc 文件中定义,并具有编号或命名的资源,每个资源都有一个类型和一个数据块。该
    Win32 资源编译器 rc.exe 将 .rc 文件编译为二进制 .res 文件,然后可以将其添加到生成的可执行文件中。

    使用 Win32 FindResource 访问 Win32 资源和 LoadResource功能。

    Win32 资源通过将它们添加到 .rc 文件来嵌入到 C++ 应用程序中,该文件被编译为 .res 文件并链接到可执行文件中。也可以在事后使用 rc.exe 程序添加它们。对于 C# 和 VB.NET 应用程序,MSBuild 可以向它通过 Csc 或 Vbc 编译器创建的可执行文件添加一个预构建的 .res 文件,或者它可以为您构建一个默认文件。 C# 和 VB.NET 都无法从 .rc 文件构建非默认 .res 文件,并且没有 MSBuild 任务可以为您执行此操作。

    您可以通过在 Visual Studio 中使用 File -> Open 打开 .exe 或 .dll 文件本身来查看 .exe 或 .dll 中的 Win32 资源。

    典型的 C、C++ 或 MFC 应用程序将有许多 Win32 资源,例如每个对话框都由一个资源指定。

    典型的 WPF 应用程序将只有三个由 C# 或 VB.NET 编译器构建的默认 Win32 资源:版本资源、RT_MANIFEST 和应用程序图标。这些资源的内容是根据代码中的Assembly 属性和<ApplicationIcon> 构造的。 .csproj 或 .vbproj 文件中的元素。

    这是 JumpList 正在寻找的资源类型。

    嵌入式资源

    “嵌入式资源”是一种 NET Framework 资源。包含这些资源的数据结构由 CLR 以更有利于托管代码访问的方式进行管理。每个资源都由一个字符串名称标识,按照惯例,该名称以与资源相关联的类的命名空间开头。

    嵌入资源只是带有名称的二进制数据块。实际数据类型要么被调用者知道,要么从名称推断出来,类似于文件系统中的文件。例如,名称以“.jpg”结尾的嵌入资源很可能是 JPEG 文件。

    使用 Assembly.GetManifestResourceStream 访问嵌入式资源和它的 sibling GetManifestResourceInfoGetManifestResourceNames .

    通过将文件添加到项目并将构建操作设置为“嵌入资源”,嵌入的资源被嵌入到 .exe 和 .dll 文件中。

    您可以在 .exe 或 .dll 中查看嵌入资源,方法是在 NET Reflector 中打开它并查看“Resources”文件夹。

    嵌入式资源通常在 WinForms 中使用,但几乎从不在 WPF 中使用。

    资源集 (.resx/.resources)

    可以将多个 NET Framework 对象(例如字符串和图标)组合到一个“资源集”数据结构中,该数据结构作为单个 NET Framework 嵌入式资源存储在 .exe 中。例如,WinForms 使用它来存储图标和字符串等不容易包含在生成的代码中的内容。

    可以使用 ResourceManager 单独检索资源集中的对象。和 ResourceSet CLR 定义的类。

    资源集中的对象由 .resx 文件在源代码中定义。数据可以直接在 .resx 文件中(如字符串的情况)或由 .resx 文件引用(如图标的情况)。项目构建时,每个 .resx 文件指定的内容被序列化为二进制形式,并存储为单个嵌入式资源,扩展名为“.resx”并替换为“.resources”。

    您可以通过在 NET Reflector 中打开 .exe 或 .dll、打开资源文件夹、单击“.resources”文件并查看右侧 Pane 中的项目来查看资源集中的对象。

    许多 WinForms 时代的功能都以类似于旧的 Win32 .rc 文件的方式常用 .resx 文件和 ResourceSets 来存储多个资源,例如字符串。 WinForms 本身也使用它们将设置存储在不能进入后面代码的表单上。

    WPF 应用程序几乎从不使用 ResourceSet 中的任意对象,尽管 WPF 本身在内部使用 ResourceSet 来存储已编译的 XAML。

    XAML 资源

    WPF XAML 资源是存储在 ResourceSet 中的已编译 XAML 文件。资源集中的名称是原始文件名,其中“.xaml”替换为“.g.baml”。内容可以是任何有效的 XAML,最常见的类型是 Window、Page、UserControl、ResourceDictionary 和
    应用。

    可以使用 Application.LoadComponent() 加载 WPF 资源或通过在 WPF 上下文中引用原始 XAML 文件名。此外,任何有代码隐藏的 WPF 资源(由 x:Class 指定)将自动加载并应用于在其 InitializeComponent 期间为该类创建的每个对象。打电话。

    WPF 资源是通过将 .xaml 文件添加到项目并将其构建操作设置为“资源”、“页面”或“ApplicationDefinition”来创建的。这会导致编译器将文件编译为 BAML 并将其添加到适当的 ResourceSet。

    您可以查看 .exe 或 .dll 中的 XAML 资源,方法是在安装了 BamlViewer 加载项的 NET Reflector 中打开它,从菜单中选择工具 -> BAML 查看器,然后使用 BAML 查看器浏览到特定的 .g.baml .resources 中的文件。

    ResourceDictionary 中的 WPF 资源

    在 WPF 中,几乎所有所谓的“资源”都是 ResourceDictionary 中的条目。 ResourceDictionaries 在 XAML 中描述,在其他对象(如 Windows 和 UserControls)中,或在仅包含 ResourceDictionary 的单独 XAML 文件中。每个都由“x:Key”标识,它可以是任何对象类型。资源本身也可以是任何对象类型。

    可以使用 {StaticResource} 在 XAML 中引用 WPF 资源和 {DynamicResource}标记扩展,或者可以使用 FindResource 在代码中加载.

    通过将 WPF 资源添加到包含 <ResourceDictionary> 中的 ResourceDictionary 的 XAML 文件,WPF 资源被添加到 ResourceDictionary。元素并给他们一个 x:Key属性。

    WPF资源在WPF中被广泛使用,包括画笔、样式、数据、几何图形、模板等。

    您可以通过浏览上述 XAML 资源以及查看 ResourceDictionary 标记内部的每个资源来查看 .exe 或 .dll 中的 WPF 资源。

    在 C# 或 VB.NET 可执行文件中包含 Win32 资源

    如何轻松地将任意 Win32 资源嵌入 C# 或 VB.NET .exe

    您会从上面的讨论中注意到,除了 Win32 资源之外,很容易将每种类型的资源添加到 C# 或 VB.NET 应用程序中。为简化此操作,您可以添加额外的构建任务和目标。方法如下:
  • 构建一个包含单个“Win32ResourceCompiler”构建任务的项目并编译它
  • 创建一个包含单个目标的 .targets 文件,该目标使用此任务将 .rc 文件自动构建为 .res
  • 将您的项目设置为使用生成的 .res 文件

  • 任务非常简单:
    public class Win32ResourceCompiler : ToolTask
    {
      public ITaskItem Source { get; set; }
      public ITaskItem Output { get; set; }
    
      protected override string ToolName { get { return "rc.exe"; } }
    
      protected override string GenerateCommandLineCommands()
      {
        return @"/r /fo """ + Output.ItemSpec + @""" """ + Source.ItemSpec + @"""";
      }
    
      protected override string GenerateFullPathToTool()
      {
        // TODO: Return path to rc.exe in your environment
      }
    }
    

    .targets 文件也很简单。这将是这样的:
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
      <UsingTask TaskName="SomeNamespace.Win32ResourceCompiler" AssemblyFile="Something.dll" />
    
      <PropertyGroup>
        <CoreCompileDependsOn>$(CoreCompileDependsOn);CompileWin32RCFile</CoreCompileDependsOn>
      </PropertyGroup>
    
      <Target Name="CompileWin32RCFile" Outputs="@(Win32RCFile->'%(filename).res')">
        <Win32ResourceCompiler
          Source="@(Win32RCFile)"
          Output="@(Win32RCFile->'%(filename).res')" />
      </Target>
    </Project>
    

    现在在 .csproj 文件中,添加对 .targets 文件的引用:
    <Import Project="Win32ResourceCompiler.targets" />
    

    当然你需要给你的 .rc 文件一个 Win32RCFile 文件类型:
    <ItemGroup>
      <Win32RCFile Include="MyWin32Resources.rc" />
    </ItemGroup>
    

    通过此设置,您可以创建一个传统的 Win32 .rc 文件来指定您的所有 Win32 资源,包括您的版本、 list 、应用程序图标以及您想要的任意数量的附加图标。每次编译时,所有这些 Win32 资源都会添加到您的 .exe 文件中。

    这需要一点时间来设置,但从长远来看比手动编辑 .res 文件更令人满意和更简单。

    您可以在 .rc 文件中指定多个图标,如下所示:
    1 ICON ApplicationIcon.ico
    2 ICON JumpListIcon.ico
    3 ICON AnotherIcon.ico
    

    Here是可在 .rc 文件中使用的所有资源定义语句的文档。

    另请注意,上面的 .targets 文件是一时兴起的,尚未经过测试。可以找到有关 MSBuild(.csproj 和 .targets)文件语法的文档 herehere ,并且 .targets 文件的好例子可以在 c:\Windows\Microsoft.NET\Framework\v3.5 目录中找到)。

    关于wpf - 将图标作为资源嵌入到 WPF 应用程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3024220/

    相关文章:

    c# - 字典到 ListView TwoWay 绑定(bind) - 可能吗?

    wpf - 在 WPF 按钮中显示点对点进度

    android - 以良好的质量和内存效率从资源中缩小位图

    javascript - 让 $resource.query 工作 AngularJS

    wpf - {0}对Setter.Value无效。唯一受支持的MarkupExtension类型是DynamicResourceExtension和BindingBase或派生类型

    java - 无法从外部 Jar 文件检索资源

    c# - 更改不透明度时窗口不会重新绘制

    wpf - 从两个不同的 DataTriggers 为同一属性设置动画

    c# - 如何获取资源文件的路径?

    c# - 如何将大文件添加到 C# 项目中的资源?