Is it possible to access resources from a differen

2019-02-11 16:30发布

问题:

I've got a rather large solution with many projects in it. Ideally I'd like to create a Resources project that contains all the embedded icons I need throughout my application.

I've read articles where people are referencing them through code, but is it possible to get access to this project's resources in the designer? In other words, I'd like to select the resources when clicking on the BackgroundImage property of a form in the designer.

If not, what sort of architecture should I consider when trying to decouple my resources from my main project? It's probably not a smart idea to release a 100mb executable everytime I modify a line of code or two.

回答1:

From the best I can tell, you can NOT manipulate resources from other assemblies in the designer. Only the one(s) from the current project.

Here’s how I would do it:

Create a Class Library Project. In the Library, Add | New Item | Resources File. Add the Resources (images, icons) to that file (ex: Resource1.resx). In a Class in that Library add public members that return the resources.

public static class Class1
{
    public static Bitmap Image1 { get { return Resource1.Image1; } }
    public static Bitmap Image2 { get { return Resource1.Image2; } }
}

Now in your project reference the Class Library and now can programmatically set the resources at runtime.

public Form1()
{
    InitializeComponent();

    this.BackgroundImage = ClassLibrary1.Class1.Image1;
}

But unfortunately you can’t use the designer. :( However, by doing this you will not need to redistribute that dll if you don't make any changes to the resources in it.



回答2:

I'd like to create a Resources project that contains all the embedded icons I need throughout my application.... I'd like to select the resources when clicking on the BackgroundImage property of a form in the designer.

You can use Resources from another assembly but unfortunately for the reasons explained below you cant do it through the designer.

In your Resources project add a Form with a picturebox and set the BackgroudImage. This is simply in order to add an Image to the projects Resouces.resx and Resouces.Designer.cs. We can delete the Form with picturebox after the image is added as a Resource.

In the Resources project go to the Resouces.Designer.cs and change the classes scope to Public and change the image methods scope from Internal to Public:

public static System.Drawing.Bitmap SO_down {
    get {
        object obj = ResourceManager.GetObject("SO down", resourceCulture);
        return ((System.Drawing.Bitmap)(obj));
    }
}

In the project that consumes the Resources DLL you need to set BackGroundImages NOT to use its own resources:

Before:

this.pictureBox1.BackgroundImage = global::WinFormWithSatelliteResources.Properties.Resources.SO_down;

After:

this.pictureBox1.BackgroundImage = global::SatResources.Properties.Resources.SO_down;

what sort of architecture should I consider when trying to decouple my resources from my main project? It's probably not a smart idea to release a 100mb executable everytime I modify a line of code or two.

These days most businesses are happy to rely on the internet. You know how you can version resources, like MyStyle22022013.CSS and webbrowsers wont fetch the resource if they already have a up-to-date copy. I am suggested a similar strategy, put all these image resources online so you can update resources without having to package and deploy them.

When you think about it like this, why even bother with a assembly full of resources? Maze well just pull resources from the internet and use them from the file system.

If initial internet access (for downloading resources) isn't an option @jross answer seems perfectly viable. These days though I dont imagine you plan on releasing this on CD.



回答3:

I've found a working way to share a resources file between many projects and keep VS Designer compatibility (works with VS 2012), it is no complicated :

  1. Create a new resources file in your source project (named in my example SharedResources.resx)

  2. Open SharedResources.resx in Designer and change Access Modifier to Public

  3. Open the .csproj of your new project file with notepad and add following code into the <ItemGroup> which contains the <compile Include="MyForm.cs"> : (will include *.resx and *.Designer.cs as link without compilation and with special namespace)

    <EmbeddedResource Include="MY_SOURCE_PROJECT_FOLDER\Properties\SharedResources.resx">
      <Generator>PublicResXFileCodeGenerator</Generator>
      <Link>SharedResources.resx</Link>
      <LastGenOutput>SharedResources.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
      <CustomToolNamespace>MY_SOURCE_PROJECT_NAMESPACE.Properties</CustomToolNamespace>
    </EmbeddedResource>
    <None Include="MY_SOURCE_PROJECT_FOLDER\Properties\SharedResources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>SharedResources.resx</DependentUpon>
      <DesignTime>True</DesignTime>
    </None>
    
  4. Replace MY_SOURCE_PROJECT_FOLDER with the relative path of your project containing the resources and replace MY_SOURCE_PROJECT_NAMESPACE with namespace specified in the generated file SharedResources.Designer.cs (should be your global project's namespace)

  5. Enjoy !

WARNING :

Sometimes VS makes an other automatic change in the **.Designer.cs* shared file which will make a failure, please ensure property ResourceManager still points to the root shared file.

IMPORTANT :

  • When you add new resources in your resx file, open it from the source project or file will be added in wrong folder !
  • When you just added a new resource, if it does not appear in the new project, simply restart VS, it should work