Проблема с общими ресурсами WinForms между проектами в Visual Studio
Я переместил все ресурсы изображений в большом многопроектном решении в новый проект, специально созданный для общих ресурсов.
Добавление новой ссылки на другие проекты, в которых используются общие изображения, работает должным образом. Изображение в выбранной кнопке ниже продолжает появляться в конструкторе, но с проблемами.
В VS Designer я не могу выбрать общие ресурсы в редакторе изображений, вместо этого нужно вручную редактировать код дизайнера.
В частности, в диалоговом окне "Редактор изображений" (доступ к которому осуществляется из свойства "Изображение" существующего элемента управления) я выбираю "Выбрать из файла / ресурса...", чтобы открыть диалоговое окно "Выбор ресурса" (показано). Там, где я использовал доступ ко всем локальным ресурсам проекта (Resources.resx), я хотел бы сейчас добавить доступ к новому проекту общих ресурсов. В идеале, я бы добавил второй элемент в раскрывающемся списке, который переключается на resx для проекта общих ресурсов.
Как это может быть сделано? Есть ли способ лучше?
7 ответов
Я смог поделиться файлом resx между проектами и использовать его в конструкторе в VS 2008 SP1 (не знаю, другие версии). В отличие от других подходов, здесь ресурсы статически и динамически распределяются, поэтому во время выполнения действительно существует одна копия общих ресурсов. Никаких потерь памяти или памяти, простота обслуживания с множеством проектов.
Следуйте инструкциям и скажите, работает ли он для вас:
- Создать проект класса Ресурсы;
- Создайте файл ресурсов (зайдите в Свойства -> Ресурсы проекта);
- Переместите файл ресурсов (по умолчанию Resources.resx) в корень проекта;
- Переименуйте файл ресурсов Resources.resx -> GlobalResources.resx;
- Измените модификатор файла ресурсов на Public (дважды щелкните файл ресурсов, "Access Modifier" -> "Public");
- Скопируйте любой файл ресурсов в корневой каталог проекта;
- Добавьте любой ресурс в файл ресурсов, используя "Добавить существующий файл" и выбрав ресурсы в корневом каталоге проекта.
Проект в обозревателе решений должен выглядеть следующим образом:
Теперь в любом проекте вам нужен файл resx, которым вы хотите поделиться:
- Добавить проект "Ресурс" как зависимость;
Отредактируйте вручную файл проекта (*.csproj) и добавьте следующие строки в файл ресурсов ItemGroup (создайте файл локальных ресурсов, если вы хотите его увидеть):
<ItemGroup> ... <EmbeddedResource Include="..\Resources\GlobalResources.resx"> <Link>GlobalResources.resx</Link> <Generator>ResXFileCodeGenerator</Generator> <LastGenOutput>GlobalResources.Designer.cs</LastGenOutput> <CustomToolNamespace>Resources</CustomToolNamespace> </EmbeddedResource> ... </ItemGroup>
Очевидно, что атрибут "Включить" должен быть правильным относительным путем к GlobalResources.resx.
- Используйте ресурсы в конструкторе, как вы просили.
В моем проекте следующие строки создаются и добавляются в проект автоматически, когда я делаю это:
<Compile Include="..\Resources\GlobalResources.Designer.cs">
<Link>GlobalResources.Designer.cs</Link>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>GlobalResources.resx</DependentUpon>
</Compile>
Если они не добавлены, добавьте их вручную.
Теперь проект должен выглядеть следующим образом в обозревателе решений (файлы подобия должны быть помечены по-другому):
Последние два шага:
- Нажмите на ссылку "GlobalResources.resx" и в свойствах установите "None" как "BuildAction". "Пространство имен пользовательских инструментов" уже должно быть установлено на "Ресурсы";
- Нажмите на ссылку "GlobalResources.Designer.resx" и в свойствах установите "None" в качестве "BuildAction".
И все готово: к этому моменту вы действительно сможете использовать ресурсы, которые вы добавили в общий ресурс в конструкторе, выбрав "GlobalResources.resx" в диалоговом окне "Файл ресурсов проекта" вашего вопроса. И, как сказано, он действительно доступен даже во время выполнения! На панели "Свойства" вы должны увидеть полное пространство имен и класс внешнего проекта. Если вы удалите зависимость от проекта "Ресурс", он даже не скомпилируется. Если это не работает для вас, настаивайте до тех пор, пока это не сработает, и в случае, скажите, где руководство не так. Это должно работать! Дай мне знать.
Я недавно столкнулся с той же проблемой. Посмотрел документацию по MS, но не смог найти хороших решений. В конечном итоге мне удалось получить редактор изображений в конструкторе WinForms для распознавания файлов ресурсов из других проектов, используя метод, описанный ниже. Это хакерство - если у кого-то есть более чистое решение, которым он хочет поделиться, пожалуйста, напишите. Я проверил это только на VS 2008.
Прежде чем начать, я должен сказать, что если вы просто хотите сделать элементы в файле Resources.resx доступными для других проектов, вы можете просто отредактировать его свойства и установить для общего доступа модификатор доступа для сгенерированного класса, чтобы он использовал PublicResXFileCodeGenerator. Приведенная ниже гимнастика необходима только в том случае, если вы хотите, чтобы дизайнеры WinForms брали изображения внутри этого файла ресурсов, как описано в посте выше от Дугласа.
Скажите, что ваше решение имеет следующую схему. Здесь важно пространство имен по умолчанию для различных проектов (щелкните правой кнопкой мыши узел проекта в обозревателе решений -> Свойства -> вкладка "Приложение"), поэтому я поместил его в квадратные скобки после имен проектов.
- MySolution
- SharedProject (пространство имен по умолчанию = SharedProject)
- SharedProject.csproj
- WinFormsProject1 (пространство имен по умолчанию = WinFormsProject1)
- WinFormsProject1.csproj
- WinFormsProject2 (пространство имен по умолчанию = WinFormsProject2)
- WinFormsProject2.csproj
- SharedProject (пространство имен по умолчанию = SharedProject)
Вы хотите создать файл ресурсов в SharedProject, содержащий изображения, которые могут использоваться WinFormsProject1 и WinFormsProject2.
Сначала создайте новый файл Resource в корне SharedProject, назовем его SharedResources.resx. Важно, чтобы этот файл использовал ResXFileCodeGenerator, а не PublicResXFileCodeGenerator, по причинам, которые станут понятны позже.
Отредактируйте SharedResources.resx в Visual Studio и добавьте ресурсы изображений, которыми вы хотите поделиться. Visual Studio также должна сгенерировать для вас файл класса внутри SharedProject с именем SharedResources.designer.cs.
Ваше решение теперь должно выглядеть так:
- MySolution
- SharedProject (пространство имен по умолчанию = SharedProject)
- SharedProject.csproj
- SharedResources.resx
- SharedResources.Designer.cs
- WinFormsProject1 (пространство имен по умолчанию = WinFormsProject1)
- WinFormsProject1.csproj
- WinFormsProject2 (пространство имен по умолчанию = WinFormsProject2)
- WinFormsProject2.csproj
- SharedProject (пространство имен по умолчанию = SharedProject)
Если вы откроете SharedProject.csproj в текстовом редакторе, вы должны увидеть следующие записи:
<EmbeddedResource Include="SharedResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>SharedResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Include="SharedResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>SharedResources.resx</DependentUpon>
</Compile>
Теперь вам нужно сделать ресурсы доступными внутри WinFormsProject1. Для этого вам нужно отредактировать WinFormsProject1.csproj в текстовом редакторе, поскольку некоторые свойства, которые нужно установить, не предоставляются в Visual Studio.
Откройте файл WinFormsProject1.csproj и добавьте следующее в ItemGroup:
<Compile Include="..\SharedProject\SharedResources.Designer.cs">
<Link>SharedResources.Designer.cs</Link>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>SharedResources.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="..\SharedProject\SharedResources.resx">
<Link>SharedResources.resx</Link>
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>SharedResources.Designer.cs</LastGenOutput>
<CustomToolNamespace>SharedProject</CustomToolNamespace>
<LogicalName>SharedProject.SharedResources.resources</LogicalName>
</EmbeddedResource>
Ключевыми вещами здесь являются CustomToolNamespace и LogicalName. По умолчанию Visual Studio использует пространство имен проекта по умолчанию для именования ресурсов и создания файла *.Designer.cs. Поскольку SharedProject и WinFormsProject1 имеют разные пространства имен по умолчанию, поведение по умолчанию приводит к несовместимости ресурса, встроенного в WinFormsProject1, с файлом *.Designer.cs, который находится внутри SharedProject. Этого можно избежать, переопределив CustomToolNamespace и LogicalName.
Теперь сделайте то же самое для WinFormsProject2.csproj. Вернитесь в Visual Studio. Он заметит, что вы изменили файлы csproj и попросит перезагрузить проекты - выберите "перезагрузить". Вы должны обнаружить, что теперь вы можете выбирать изображения из SharedResources.resx при разработке форм в WinFormsProject1 и WinFormsProject2.
По сути, все это делает VS включающим файл SharedResources.resx из SharedProject в проектах WinFormsProject1 и WinFormsProject2. Существует только один исходный файл.resx (в SharedProject), но когда вы компилируете решение, на самом деле будет три идентичных класса с именем SharedProject.SharedResources, по одному в каждой из трех сборок, но, поскольку все они имеют внутреннюю видимость, они не будут мешать друг с другом, даже если вы добавите ссылку между проектами.
ОБМЕН РЕСУРСАМИ МЕЖДУ ПРОЕКТАМИ В VS2012
в 3 простых шага, используя только дизайнер!
- создайте проект и добавьте свои ресурсы, чтобы делиться ими как обычно
- создать другой проект и "добавить как ссылку" resources.resx первого проекта в диалоге "добавить существующий элемент", доступный из контекстного меню
- выберите изображения из связанного файла ресурсов по желанию; это можно выбрать в раскрывающемся меню "файл ресурсов проекта" в диалоге "выбор ресурса", доступном из панели свойств
VOILA!
Для Visual Studio 2015+
Существует простой, простой способ, который не поддерживается в пользовательском интерфейсе VisualStudio. Так что, если вы не боитесь редактировать файлы проекта, читайте дальше.
Если вы еще этого не сделали, добавьте новый общий проект в решение.
Если вы еще этого не сделали, включите новый общий проект в качестве ссылки на общий проект для своего периферийного проекта.
Обратите внимание, как этот общий проект включен в периферийный проект (.csproj
файл) прямым способом:
<Import Project="..\Common\Common.projitems" Label="Shared" />
Таким образом, даже если пользовательский интерфейс VS не предоставляет его, все в общем проекте (.projitems
файл) входит непосредственно в периферийный проект. Добавление следующих определений ресурсов в общий проект (.projitems
файл) будет включать их непосредственно в ваш периферийный проект. Но, потому что Resource
Элемент не поддерживается пользовательским интерфейсом VS для общих проектов, эти файлы будут скрыты и проигнорированы в IDE.
<ItemGroup>
<Resource Include="$(MSBuildThisFileDirectory)Resources\one 16x16.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\one 64x64.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\one.ico" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\two 16x16.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\three 16x16.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\four 16x16.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\five 16x16.png" />
<Resource Include="$(MSBuildThisFileDirectory)Resources\six 16x16.png" />
</ItemGroup>
Наконец, тогда как ресурсы вашего периферийного проекта могут иметь относительные пути (например, ".\Resources\main.ico"
), эти ресурсы скомпилированы в ваш периферийный проект с базовыми идентификаторами, а не абсолютными или относительными. например:
<Window x:Class="Common.Shared"
...
Icon="one.ico">
<Window.Resources>
<ResourceDictionary>
<BitmapImage x:Key="one64" UriSource="one 64x64.png"/>
</ResourceDictionary>
</Window.Resources>
Вам нужно только добавить новый проект класса с файлом RESX, куда вы включаете ресурсы (изображения, тексты и т. Д.). После в других проектах добавьте ссылку на это и используйте имя класса Resource для доступа к необходимому ресурсу, например: Project.SharedImages.Upload_64x64 (в результате получается растровое изображение, готовое к использованию в этом случае)
Используйте следующий подход для проектов стилей SDK или скопируйте содержимое файла .targets (не проверялось) для проектов стилей, отличных от SDK.
1. Создайте следующий файл рядом с вашим решением. Замените заполнители соответствующей информацией о вашем глобальном ресурсе. Назовите его, например, «IncludeGlobalResources.targets».
<Project>
<!--Makes it possible to select the Images of My.Custom.Namespace.MyGlobalResourceProject in your Projects WindowsForms-Designers-->
<!--See https://stackoverflow.com/questions/1100455/issue-with-shared-winforms-resources-across-projects-in-visual-studio-->
<ItemGroup>
<None Include="..\My.Namespace.MyGlobalResourceProject\MyGlobalImages.resx">
<Link>MyGlobalImages.resx</Link>
<LastGenOutput>MyGlobalImages.Designer.cs</LastGenOutput>
<Generator>none</Generator> <!-- Without this line you will get bugs as the referencing project will re-generate the source file with wrong namespaces -->
</None>
</ItemGroup>
<ItemGroup>
<None Include="..\My.Namespace.MyGlobalResourceProject\MyGlobalImages.Designer.cs">
<Link>MyGlobalImages.Designer.cs</Link>
<DependentUpon>MyGlobalImages.resx</DependentUpon>
</None>
</ItemGroup>
</Project>
2. Перейдите в файл проекта (у меня были проекты в стиле SDK), где вы хотите использовать глобальный ресурс. Ссылка на созданный файл:
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)\IncludeGlobalResources.targets" />
(...)
3: Теперь вы можете просто добавить 2. к каждому проекту, в котором хотите использовать глобальный ресурс. Также вы можете легко расширить файл другими глобальными ресурсами.
Ответ Чарли отлично работает!
Небольшое изменение: если вы хотите пропустить последние два шага, используйте эту версию включенных элементов при изменении файла проекта.
<None Include="..\Resources\GlobalResources.resx">
<Link>GlobalResources.resx</Link>
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>GlobalResources.Designer.cs</LastGenOutput>
<CustomToolNamespace>Resources</CustomToolNamespace>
</None>
<None Include="..\Resources\GlobalResources.Designer.cs">
<Link>GlobalResources.Designer.cs</Link>
<DependentUpon>GlobalResources.resx</DependentUpon>
</None>