在Visual Studio中跨项目共享WinForms资源的问题

时间:2009-07-08 20:43:01

标签: winforms visual-studio-designer

我已将大型多项目解决方案中的所有图像资源移动到专为共享资源创建的新项目。

向使用共享映像的其他项目添加新引用正在按预期工作。下面所选按钮中的图像继续出现在设计器中但有问题。

在VS Designer中,我无法在图像编辑器中选择共享资源,而是手动编辑设计器代码。

更具体地说,在图像编辑器对话框中(从现有控件的“图像”属性访问),我选择“从文件/资源​​中选择...”以弹出“选择资源”对话框(如图所示)。我曾经访问过所有本地项目资源(Resources.resx),我现在想要添加对新共享资源项目的访问权限。理想情况下,我会在显示的下拉列表中添加第二项,切换到共享资源项目的resx

如何做到这一点?还有更好的方法吗?

alt text

6 个答案:

答案 0 :(得分:20)

我能够在项目之间共享一个resx文件,并在VS 2008 SP1的设计器中使用它(dunno其他版本)。与其他方法不同,这里的资源是静态和动态共享的,因此在运行时实际上只有一份共享资源。没有存储或内存浪费,大量项目易于维护。

按照指南告诉我它是否适合您:

  • 创建一个类项目Resources;
  • 创建资源文件(转到属性 - >项目资源);
  • 将资源文件(默认为Resources.resx)移动到项目的 root ;
  • 重命名资源文件Resources.resx - > GlobalResources.resx;
  • 将资源文件修饰符修改为Public(双击资源文件,“Access Modifier” - > gt;“Public”);
  • 将任何资源文件复制到项目的根目录;
  • 使用“添加现有文件”将任何资源添加到资源文件,然后在项目的 root 目录中选择资源。

解决方案资源管理器中的项目应如下所示:

enter image description here

现在,在任何项目中,您都需要共享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>
    

显然,“Include”属性应该是GlobalResources.resx的正确相对路径。

  • 按照您的要求使用设计器中的资源。

在我的项目中,生成以下行并在执行此操作时自动添加到项目中:

<Compile Include="..\Resources\GlobalResources.Designer.cs">
  <Link>GlobalResources.Designer.cs</Link>
  <AutoGen>True</AutoGen>
  <DesignTime>True</DesignTime>
  <DependentUpon>GlobalResources.resx</DependentUpon>
</Compile>

如果未添加,请手动添加。

现在,在解决方案资源管理器中,项目应该如下所示(相似的文件应该标记不同):

enter image description here

最后两步:

  • 单击链接的“GlobalResources.resx”,并在Properties上将“None”设置为“BuildAction”。 “自定义工具命名空间”应已设置为“资源”;

enter image description here

  • 点击链接的“GlobalResources.Designer.resx”,然后点击属性设置“无”作为“BuildAction”。

enter image description here

您已经完成了:此时您应该能够使用您在设计器中的共享resx中添加的资源,在您的问题的“项目资源文件”对话框中选择“GlobalResources.resx”。而且据说它甚至在运行时也是真的共享!在“属性”面板中,您应该看到外部项目的完整命名空间和类。如果删除对“Resource”项目的依赖性,它甚至不会编译。如果它不适合你,请坚持到它工作,并告诉我哪个指南是错误的。它必须工作!让我知道。

答案 1 :(得分:8)

我最近遇到了同样的问题。看看MS文档,但找不到任何好的解决方案。我最终能够使WinForms设计器中的图像编辑器使用下面描述的方法识别来自其​​他项目的资源文件。这是hacky - 如果有人有一个更清洁的解决方案,他们想分享请发布。我只在VS 2008上测试了这个。

在开始之前,我应该说如果你只想让其他项目可以访问Resources.resx文件中的项目,你可以只编辑它的属性并将生成的类的访问修饰符设置为public,这样它就可以使用PublicResXFileCodeGenerator 。只有当你想让WinForms设计师在这个资源文件中拾取图像时才需要下面的体操,如Douglas上面的帖子所述。

假设您的解决方案具有以下布局。各种项目的默认命名空间(右键单击解决方案资源管理器中的项目节点 - &gt;属性 - &gt;应用程序选项卡)在这里很重要,所以我在项目名称后面的括号中放了它。

  • MySolution
    • SharedProject(默认名称空间= SharedProject)
      • SharedProject.csproj
    • WinFormsProject1(默认名称空间= WinFormsProject1)
      • WinFormsProject1.csproj
    • WinFormsProject2(默认名称空间= WinFormsProject2)
      • WinFormsProject2.csproj

您希望在 SharedProject 中创建一个资源文件,其中包含可由 WinFormsProject1 WinFormsProject2 使用的图像。

首先在 SharedProject 的根目录中创建一个新的资源文件,让我们称之为 SharedResources.resx 。重要的是,此文件使用ResXFileCodeGenerator而不是PublicResXFileCodeGenerator,其原因将在以后变得清晰。

在Visual Studio中编辑 SharedResources.resx 并添加要共享的图像资源。 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.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文件并要求重新加载项目 - 选择“重新加载”。在 WinFormsProject1 WinFormsProject2 中设计表单时,您会发现现在可以从 SharedResources.resx 中选择图像。

基本上所有这一切都是让VS在 WinFormsProject1 WinFormsProject2 <中包含来自 SharedProject SharedResources.resx 文件/ em>项目。只有一个.resx源文件(在 SharedProject 中),但是当你编译解决方案时,实际上会有三个相同的类叫做 SharedProject.SharedResources ,每个类都有一个三个程序集,但由于它们都具有内部可见性,即使您在项目之间添加引用,它们也不会相互干扰。

答案 2 :(得分:6)

VS2012项目之间的资源共享

仅使用设计师的3个简单步骤!

  1. 创建项目并添加您的资源以照常共享
  2. 创建另一个项目并“添加为链接”第一个项目的resources.resx在“添加现有项目”对话框中,可从上下文菜单中访问
  3. 根据需要从链接的资源文件中选择图像;这可以在“选择资源”对话框的“项目资源文件”下拉菜单中选择,可从属性窗格访问
  4. VOILA!

答案 3 :(得分:1)

您只需要添加一个带有RESX文件的新类项目,其中包含资源(图像,文本等)。在其他项目之后添加对此的引用并使用Resource类名称来访问所需的资源,例如:Project.SharedImages.Upload_64x64(结果是在这种情况下可以使用的Bitmap)

答案 4 :(得分:0)

对于Visual Studio 2015 +

VisualStudio UI不支持简单明了的方法。因此,如果您不害怕编辑项目文件,请继续阅读。

如果您还没有这样做,请在解决方案中添加一个新的共享项目。Add a New Shared Projecct

如果您还没有这样做,请将新的共享项目包含为外围项目的共享项目参考。enter image description here

请注意这个共享项目如何以直接的方式包含在外围项目(.csproj文件)中:

<Import Project="..\Common\Common.projitems" Label="Shared" />

因此,即使VS UI没有公开它,共享项目(.projitems文件)中的所有内容都直接包含在外围项目中。将以下资源定义添加到共享项目(.projitems文件)将直接包含在外围项目中。但是,由于共享项目的VS UI不支持Resource元素,因此这些文件将在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"),但这些资源会使用基本ID编译到您的外围项目中,而不是绝对的或相对的。 e.g:

<Window x:Class="Common.Shared"
  ...
  Icon="one.ico">
  <Window.Resources>
    <ResourceDictionary>
      <BitmapImage x:Key="one64" UriSource="one 64x64.png"/>
    </ResourceDictionary>
  </Window.Resources>

答案 5 :(得分:0)

查理的回答非常有效!

只是一个小改动:如果你想跳过最后两个步骤,当你修改一个项目文件时,使用这个版本的包含项。

<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>