Click here to Skip to main content
15,880,405 members
Please Sign up or sign in to vote.
5.00/5 (5 votes)
See more:
Hi all,
Our application consists of several solutions. It uses MEF to plugin functional parts, that is all fine.

I now try to find a way to share resources across all of those projects.
Currently I create a dll containing a public resource file hosting images I need in all of my other projects.
I reference the dll containing the resource file and I can access all of the images... from code.

Is there a way to have the designer support such a referenced rersource dll?
I'd like to select the images in the designer and not manipulate the Form.Designer.cs or initialize them myself from code.

I also tried to inherit from the Resource.Designer.cs, but that also didn't work out. I can access the images, but again only from code (beside the fact that it is regenerated every time I add/remove elements from the inheriting resource file - which won't be a big problem because logically it should not be changed)

Any help is kindly appreciated,
cheers
Andy
Posted
Updated 26-Jan-12 4:56am
v4
Comments
fjdiewornncalwe 26-Jan-12 11:17am    
A very interesting question. +5 for that. I have no idea how to approach this one, but I'm curious to see what some of the others come up with.
hoernchenmeister 26-Jan-12 11:20am    
So am I ;)
Sergey Alexandrovich Kryukov 26-Jan-12 13:50pm    
Well, I agree, also voted 5.
You can get an idea how to approach this if you read my answer -- hope you will find it interesting, too.
--SA
BillWoodruff 26-Jan-12 12:43pm    
+5 for, as Marcus commented, a very interesting question !
Sergey Alexandrovich Kryukov 26-Jan-12 13:51pm    
I agree, also voted 5.

I you find this question interesting, you might find my answer interesting, too, please see.
--SA

1 solution

Resources are designed to be internal to the assembly. However, the problem is solvable. You need to put all resources in one or more special resource-only assemblies and provide a special facade class (or classes) used exclusively to expose the resource to the assemblies referencing your resource assemblies. A typical form of exposure should be a public static property of a static class.

(See http://en.wikipedia.org/wiki/Facade_pattern[^].)

For one thing, this will present a certain maintenance hassle: as soon as you change or add a new resource, you will need to change the facade class: add a property or modify the implementation of existing property, usually just a name if internal property. Also, it looks like a functional redundancy. (But do you have a choice without redundancy?)

From the other hand, the facade class is trivial, maintenance is not tricky, and it can give you a layer for additional flexibility, so the interface can be done in a more semantic style from the perspective of the referencing assembly (user assembly). I can explain.

For example, you need to add N images. The best way of doing it through the designer is this: you add the *.res resources using the Designer as separate image files using "Add existing file". The designer will copy the file in the project directory structure (make sure it would not produce double copies, you only need to keep the target copy in the project), add the reference file to the project file with appropriate attributes (instructing the MSBuild: embedded resource, don't copy to the output directory), it will also add the reference to the file to the resource file and — important — will auto-generate the source file. Look at this source file: you will find some static class and some static property with the name close to the name of the image file. The best thing is: if the file type is JPEG or PNG, the type of the static property is Image. Same thing with many other resource types. You don't have to use resource stream, read or convert anything; you already have a fully-initialize static Image. Or string in the case of the text file, or something else.

So far so good, but the only problem is when you use many image files, the writer of the code using the resources should use the semantic (hopefully) variable names (very good that not strings as the compiler would not able to check it they are correctly spelled), but what if there are too many? The access to the many resources is not structured.

As you have a facade class(es) in my approach, you can use the extra flexibility to restructure the access. For example, you can group those image variables into some structures by semantic criteria or even present them as a collection indexed by an enumeration type and/or enumerate in a cycle by a enumeration-type index.

(By the way, you can learn how to enumerate by a enumeration type index from my article: Enumeration Types do not Enumerate! Working around .NET and Language Limitations[^].)

—SA
 
Share this answer
 
v4
Comments
fjdiewornncalwe 26-Jan-12 16:21pm    
Of course. I totally didn't think of using the facade in this case, but should have. Well explained. +5.
Sergey Alexandrovich Kryukov 26-Jan-12 16:28pm    
Thank you, Marcus.
The "facade" in not much more then just a term and the idea. The essence is in how resources work and how assemblies can use each other.
--SA
hoernchenmeister 27-Jan-12 4:11am    
Thanks a lot SA for your explanantion.
Unfortunately I have a hard time to follow...
I got that part with the facade class though, but I somehow struggle with the rest. Would you mind helping me understanding this in its depths (no code, I really want to get the idea).

If I got it right I need a resource assembly first. So I went ahead and created a class library containing a resource file that hosts some images. I added a class too, to be able to load that assembly with a ResourceManager in case this will become useful somehow. I compiled and now I have a dll.

Then I created a WinForm project for testing purposes.
You wrote: "For example, you need to add N images. The best way of doing it through the designer is this: you add the *.res resources using the Designer as separate image files using "Add existing file""
Hopefully you don't think I am stupid, but I just don't get it ;)
I can translate it into my mother language, but I am not really sure what you mean here.
Do you mean add the *.resx file from the resource assemblies project as existing file to the test-project?


Regarding the facade, besides my tries above I created another class library project containing a resx file with some images. There I added a static class that exposes the images from the resx via an enumerator (exmpl. enum GlobalImages{Delete, Edit, New}). I am now able to get the images in other applications from code.
Just to make sure I explained my question correctly. My colleague now can use the dll and get images in a controlled way, which is really good. But for example, if he has a form with a button on it he want's to set the image for the button using the property window of the designer. Which is not possible because he can only select from .resx in the project.
Will your approach make this possible?

Thanks a lot for your efforts SA,
it is always a pleasure (even if it sometimes hard for me to follow in the first place) reading your explanations, answers and articles. I already learned a lot in the past, and will of course continue to do so in the future :)

cheers
Andy
Sergey Alexandrovich Kryukov 23-Feb-12 13:27pm    
Hi Andy,

I'll try to answer.

First, how to create resources. My "...you add the *.res resources using the Designer..." was perhaps just too short, just because I assume you will know what to do; my text was not to show the steps but to remind you about something which you could already see in the IDE. Now, to show the steps, I'll need to open the IDE...

Let's say you have just created an item in your project: [some directory node in the Solution Explorer] -- [context meny] -- Add... -- New Item... -- ["Add New Item" window"] -- [...list] -- Resource File -- selected a name "Images.res".

If will create just two files: "Images.res", and "Images.Designer.cs"; and two nodes in the Solution Explorer tree, one a child of another. When you double click (or "Open") "Images.res", you will get to the Designer window in the source code area, in a separate tab (usually); it has a smaller menu on the top: "Strings", "Add resource", etc.

You want to use "Add Resource" -- "Add Existing File". Suppose you have some image file "firstImage.png". Add it in this way. The file 1) will be copied into your project (so make sure you does not appear twice; it it was inside your project's sub-directory, you don't need it's first copy, you only need the one created by the designer), 2) it's name added to the project file (you will see it in the Solution Explorer's project tree as a node), 3) in a project, is will get the properties like a resource and "don't copy" (to the output; because it will be embedded instead), 4) it's name will be referenced in "images.res".

Now, all changes will be use in auto-generated code "Images.Designer.cs". You are not supposed to modify this code, ever, but just look into it. You will find some static variable named based on "firstImage". The type of this property is already Image. You can use it immediately through its name. You don't have to read it from resource or anything. It's already done.

Now, you create a facade class and expose some properties of the static class generated in "Images.Designer.cs" using "public".

The question is how to use them in Designer. Now, it's my turn to wonder: what, are you programming through Designer?! Well, don't do it! Designer is designed to help to do the fist demo very quickly but slow down the reuse and maintenance, to make it barely supportable and not reusable. You really need to use the Designer just to put all the panels and some (not all) of other controls to design a general layout of the form. You can modify just the names of the members (but refactorization menu is much better then the designer), and adjust such properties as Dock and Padding, to be able to see the result immediately. But even this is dangerous for support. Imagine you need padding of 5. It means that you will create a lot of different padding object with 5 and 0 (to avoid 5+5). What happens when you need to change 5 to 6 consistently? Designer sucks. Every time you do any repeated work in programming, you do something wrong. Designer is manual work, writing code is not, in contrast to common wrong believe. Setting images from resource in Designer is bad and not portable. This is good that the Designer does not support changing images taken from external resource assembly -- it helps you to avoid yet another mistake. Designer eliminates code reuse, but your question was about reuse.

More than that, using code is perfectly save. In this approach, you do not hard-code anything. Your static member in the auto-generated resource file (this is where the resource Designer is good to use) has the name which is checked up with a compiler. Should you change is, it won't compile.

--SA
hoernchenmeister 13-Mar-12 4:40am    
Hi SA,
I now understand what you explained. It's sometimes hard for me to get the "message", even if I my english is quite good (in my opinion at least).
I do know how to deal with resources, I just couldn't put it all together.
I really appreciate all the efforts you made to help me out and to explain it as nicely as you have done it.
I have finally chosen the facade approach and stopped trying to use the designer. That's also the reason for the long period of time that passed by until I finally started to write down these lines.

You made a big impact on my way of thinking regarding the use of the designer. I use the designer primarily to set up my forms and to interact with third party tools (Infragistics) that provide helper windows to adjust complex components quite fast. Additionally I use Resharper for the refractoring purposes, but I never looked at the designer itself the way you described it.
It took me some thinking and I needed to drop some opinions I gained over the years, but you are pretty much right with what you've said.
Especially the "reusability part", because I strive to create reusable things if applicable (I remeber heated discussions with my superior trying to convince him that we need libraries so that we can reuse things that have already been done before - when I started here they were pretty much on VB6 only without anything beeing reusable and on forms only).

So finally I want to thank you for your input on this topic and for the way you try to help me with my problem.
I appreciate that you tried to make me look at that problem in a different way. Isn't that the way to become better?
Moving your head into a different direction to gain knowledge instead of sticking to old habits due to comfort purposes?
I think it is.

I really got much more out of this post than I have thought in the first place.

thanks again SA and have a great day,
best regards
Andy

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900