Вставить иконки в приложение WPF как ресурс

Я пытаюсь встроить значок в мое приложение WPF, чтобы я мог его вытащить для использования в качестве значка в JumpList для Windows 7, используя следующий код:

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

Я получил его для работы, используя следующий метод: http://dennisdel.com/?p=38

Однако, это не похоже на лучший подход, и кажется, что должен быть более простой способ встроить ресурс значков в мое приложение, оставив при этом параметр " Значок и манифест" в свойствах приложения для моей программы.

Я пробовал множество методов, включая установку действия сборки значков в качестве ресурса и встроенного ресурса, но каждый раз, когда я открываю свой .exe в редакторе ресурсов, значок не появляется.

Любые предложения?

Ответ 1

Visual Studio не имеет возможности выполнить компилятор ресурсов Win32 из задачи MSBuild, и ни одна из встроенных функций для создания ресурсов не создает ресурсы. Из-за этого ваши варианты:

  • Создайте файл .res "вручную", как описано в связанной статье, или
  • Добавьте задачу сборки, чтобы вы могли вызвать компилятор ресурсов Win32 из вашего .csproj

Сначала я объясню различия между пятью различными "ресурсами", которые могут существовать в файле .exe или .dll, включая "Ресурсы Win32", которые требуется JumpList.

Затем я объясню, как создать задачу пользовательской сборки, которая позволяет встраивать произвольные ресурсы Win32 в исполняемый файл С# или VB.NET.


Пять видов ресурсов в исполняемом файле Win32

Существует пять различных видов "ресурсов", которые могут существовать в файле .exe или .dll:

  • Ресурсы Win32
  • NET Framework "Встроенные ресурсы"
  • Объекты CLR в ResourceSet
  • Ресурсы XAML
  • Ресурсы WPF (объекты в ResourceDictionary)

Ресурсы Win32

Первоначальный вид ресурса был Win32 "Resource". Этот вид ресурсов определяется в файле .rc и имеет либо нумерованные, либо именованные ресурсы, каждый из которых имеет тип и блок данных.
Компилятор ресурсов Win32, rc.exe, компилирует .rc файл в двоичный файл .res, затем может быть добавлен в результирующий исполняемый файл.

Доступ к ресурсам Win32 осуществляется с помощью функций Win32 FindResource и LoadResource.

Ресурсы Win32 встроены в приложения С++, добавив их в файл .rc, который скомпилирован в файл .res и связан с исполняемым файлом. Они также могут быть добавлены после использования программы rc.exe. Для приложений С# и VB.NET MSBuild может добавить предварительно созданный файл .res к исполняемому файлу, который он создает с помощью компилятора Csc или Vbc, или он может создать по умолчанию для вас. Ни С#, ни VB.NET не имеют возможности создавать файлы с расширением .res из-за невыполнения .res файлов, и для вас нет задачи MSBuild.

Вы можете просматривать ресурсы Win32 в файлах .exe или .dll, открыв сам файл .exe или .dll в Visual Studio, используя File → Open.

В типичном приложении C, С++ или MFC будет много ресурсов Win32, например, каждое диалоговое окно будет указано ресурсом.

Типичное приложение WPF будет иметь только три стандартных ресурса Win32, созданных компилятором С# или VB.NET: ресурс версии, RT_MANIFEST и значок приложения. Содержимое этих ресурсов построено из атрибутов Assembly в коде и в элементе <ApplicationIcon> в файле .csproj или .vbproj.

Это тот ресурс, который ищет JumpList.

Встроенные ресурсы

"Встроенный ресурс" - это ресурс NET Framework. Структура данных, содержащая эти ресурсы, управляется CLR способом, более удобным для доступа управляемым кодом. Каждый ресурс идентифицируется строковым именем, которое по соглашению начинается с пространства имен класса, с которым связан ресурс.

Вложенный ресурс - это всего лишь фрагмент двоичных данных с именем. Фактический тип данных либо известен вызывающему, либо выводится из имени, как файлы в файловой системе. Например, встроенный ресурс с именем, заканчивающимся на ".jpg", скорее всего будет JPEG файлом.

Доступ к встроенным ресурсам осуществляется с помощью Assembly.GetManifestResourceStream и его братьев и сестер GetManifestResourceInfo и GetManifestResourceNames.

Встроенные ресурсы встроены в файлы .exe и .dll, добавив файл в проект и установив действие сборки в "Встроенный ресурс".

Вы можете просмотреть встроенные ресурсы в .exe или .dll, открыв его в NET Reflector и посмотрев папку "Ресурсы".

Встроенные ресурсы обычно используются в WinForms, но почти никогда с WPF.

Наборы ресурсов (.resx/.resources)

Несколько объектов NET Framework, таких как строки и значки, могут быть объединены в единый набор данных "Набор ресурсов", который хранится в .exe как единый встроенный ресурс .NET Framework. Например, это используется WinForms для хранения таких вещей, как значки и строки, которые нелегко включить в сгенерированный код.

Объекты в наборе ресурсов могут быть получены индивидуально с помощью классов ResourceManager и ResourceSet, определенных CLR.

Объекты в наборе ресурсов определяются в исходном коде файлом .resx. Данные могут быть непосредственно в файле .resx(как в случае с строками) или ссылаться на файл .resx(как в случае с значками). Когда проект построен, содержимое, указанное каждым файлом .resx, сериализуется в двоичную форму и сохраняется как один встроенный ресурс с расширением ".resx", замененным на ".resources".

Вы можете просмотреть объекты в наборе ресурсов, открыв файлы .exe или .dll в NET Reflector, открыв папку "Ресурсы", щелкнув файл ".resources" и посмотрев на элементы в правой панели.

Многие функции эпохи WinForms обычно используют файлы .resx и ResourceSets аналогично старым файлам Win32.rc для хранения нескольких ресурсов, таких как строки. Они также используются WinForms для хранения настроек в форме, которая не может идти в коде.

Приложения WPF почти никогда не используют произвольные объекты в ResourceSets, хотя WPF сам использует ResourceSets для хранения скомпилированного XAML.

Ресурсы XAML

Ресурс WPF XAML - это скомпилированный файл XAML, который хранится внутри ResourceSet. Имя внутри набора ресурсов - это исходное имя файла с заменой ".xaml" на ".g.baml". Контент может быть любым допустимым XAML, наиболее распространенными типами являются Window, Page, UserControl, ResourceDictionary и
Применение.

Ресурсы WPF можно загружать с помощью Application.LoadComponent() или путем ссылки на исходное имя файла XAML в контексте WPF. Кроме того, любой ресурс WPF, который имеет код позади (как указано x:Class), будет автоматически загружен и применен к каждому объекту, созданному из этого класса во время его вызова InitializeComponent.

Ресурсы WPF создаются путем добавления в проект файла .xaml и установки его действия сборки на "Ресурс", "Страница" или "ApplicationDefinition". Это заставляет компилятор компилировать файл в BAML и добавлять его в соответствующий ResourceSet.

Вы можете просмотреть ресурсы XAML в .exe или .dll, открыв его в NET Reflector с установленной надстройкой BamlViewer, выбрав в меню Tools → BAML Viewer и с помощью BAML Viewer перейти к конкретному. g.baml внутри .resources.

Ресурсы WPF в ResourceDictionary

В WPF почти все так называемые "ресурсы" - это записи в ResourceDictionary. ResourceDictionaries описаны в XAML, либо в других объектах, таких как Windows и UserControls, либо в отдельных файлах XAML, которые содержат только ResourceDictionary. Каждый из них идентифицируется с помощью "x: Key", который может быть любым типом объекта. Сами ресурсы также могут быть любыми типами объектов.

Ресурсы WPF можно ссылаться в XAML с использованием расширений разметки {StaticResource} и {DynamicResource} или могут быть загружены в код с помощью FindResource.

Ресурсы WPF добавляются в ResourceDictionary, добавляя их в файл XAML, который содержит ResourceDictionary внутри элемента <ResourceDictionary> и присваивает им атрибут x:Key.

Ресурсы WPF широко используются в WPF, включая кисти, стили, данные, геометрии, шаблоны и т.д.

Вы можете просмотреть ресурсы WPF в файлах .exe или .dll, просмотрев ресурсы XAML, как описано выше, и для каждого из них, просматривающих теги ResourceDictionary, чтобы просмотреть сами ресурсы.


Включение ресурсов Win32 в исполняемый файл С# или VB.NET

Как легко встраивать произвольные ресурсы Win32 в С# или VB.NET.exe

В приведенном выше обсуждении вы отметите, что легко добавлять каждый тип ресурса в ваше приложение С# или VB.NET, за исключением ресурсов Win32. Чтобы сделать это легко, вы можете добавить дополнительную задачу сборки и задачу. Вот как:

  • Создайте проект, содержащий одну задачу сборки "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, включая вашу версию, манифест, значок приложения и столько дополнительных значков, сколько хотите. Каждый раз, когда вы компилируете, все эти ресурсы Win32 будут добавлены в ваш .exe файл.

Это займет немного времени, чтобы настроить, но гораздо более удовлетворительно и проще в долгосрочной перспективе, чем вручную редактировать файл .res.

Вы можете указать несколько значков в вашем файле .rc следующим образом:

1 ICON ApplicationIcon.ico
2 ICON JumpListIcon.ico
3 ICON AnotherIcon.ico

Здесь - документация для всех операторов определения ресурсов, которые вы можете использовать в файле .rc.

Также обратите внимание, что вышеприведенный файл .targets был напечатан на волне момента и не был протестирован. Документацию по синтаксису файлов MSBuild (.csproj и .targets) можно найти здесь и здесь, а хорошие примеры файлов .targets можно найти в каталоге c:\Windows\Microsoft.NET\Framework\v3.5).

Ответ 2

Вы можете выполнять следующие действия:

1) добавить значок в свой проект

2) измените "действие сборки" значка, добавленного в "Встроенный ресурс"

3) найдите окончательное имя вашего значка в сборке, вызвав следующий метод:

GetType().Assembly.GetManifestResourceNames()

этот метод возвращает все ресурсы, встроенные в сборку типа, возвращаемого методом GetType

например, я нашел свое имя значка: "FaraProjectDesktop.Static.NotConnected.ico"

4) после этого вы можете использовать код ниже:

notifyIcon.Icon = new System.Drawing.Icon(GetType().Assembly.GetManifestResourceStream("FaraProjectDesktop.Static.NotConnected.ico"));

Закончено