Best way to store sets of images for Windows Forms

6.3k views Asked by At

I am developing a windows forms applications and I will use sets of images (think icons). Depending on the theme, different sets of images must be chosen (I will later draw them using a Bitmap).

I was thinking of storing the images in separate files (archive files ? dlls ?) and then loading them at runtime from the main application. What would be the most effective way to do this ?

Thank you for reading.

3

There are 3 answers

4
Zenwalker On

I shall answer this considering few scenarios.

  1. Does this images change often? Then go for directory based approcach, where store it in a directory and load it up. May be you can have an xml having the names of these files to load. So name change in the files (images), just change xml.

  2. These files never changes? Then just embed those as a resources, such a way it will be embedded into your exe/dll and none can corrupt the images.

Normally i have seen folks not doing embedding.

0
Benoit Drapeau On

Did you think about using resx files (resource files)? This way, you can embed any images (icons), or whatever you like and decide to load only the resource file that are needed based on your theme (resource files can be named based on your themes names). Seems like the same problem encountered when localizing, isnt it? But to know if it is the best way of doing it (performance, memory, etc.), I can't tell.

0
havardhu On

Not sure if you got the answer you were looking for. Here's a step-by-step to create a resource dll

  1. Create a new project in visual studio, class library
  2. Add your resources (pictures) to the project (Add existing item)
  3. For each resource, in the properties window, set Build Action to Embedded resource
  4. Compile the library, produces a dll
  5. In your winforms application, you can now load this assembly at runtime (Code #1)
  6. Load the resource stream that you want and save it to a Bitmap object (Code #2)

Code #1

Assembly ambly = Assembly.LoadFile(pathToDll);

Code #2

BitMap bitMap;
// where "ns" is the default namespace of the resource project    
using (Stream resourceStream = ambly.GetManifestResourceSream("ns.image.jpg"))
{
      bitMap = BitMap.FromStream(resourceStream);
}

These are the basic techniques used for embedding resources and loading them at runtime.

Now, since you're thinking of having different themes, and store the resources for each theme in different libraries, you should have an interface that specifies some sort of resource manager, defined in your main application.

An example

interface IThemeResourceProvider
{
     Stream LoadBigLogo();
     Stream LoadSmallLogo();
} 

Then implement that interface in your resource library

public class ThemeResourceProvider : IThemeResourceProvider
{
    public Stream LoadBigLogo()
    {
         Assembly ambly = Assembly.GetExecutingAssembly();
         return ambly.GetManifestResourceStream("namespace.image.jpg");
    }

    (...)
}

Finally, instead of loading the resource directly in your main application, you instantiate the IThemeResourceProvider found in the resource library

 Assembly assembly = Assembly.LoadFile(pathToDll);

 var results = from type in assembly.GetTypes()
               where typeof(IThemeResourceProvider).IsAssignableFrom(type)
               select type;

Now you have an IEnumerable<Type> in that list. Typically, you'd only have one, but using this approach you could also host multiple sets of resources, and implement multiple IThemeResourceProviders in the same resource dll. You could e.g. identify each IThemeResourceProvider with a name, either as a property, or using a custom [Attribute] decoration on your various implementations. I'll leave the rest up to you to figure out.

But here's how to instantiate the IThemeResourceProviders in your list

foreach (var providerType in results)
{
     var constructorInfo = providerType.GetConstructor(Type.EmptyTypes);
     IThemeResourceProvider provider = constructorInfo.Invoke(null);
}

And finally, using one of these providers to get a bitmap:

BitMap bitMap;
using (Stream resourceStream = provider.LoadBigLogo())
{
      bitMap = BitMap.FromStream(resourceStream);
}