Images from a Windows Form project resource
Tags: tutorial, csharp, dotnet
Published: 2023-01-22 19:38:56

With modern technologies such as MAUI for desktop solutions there is still a place for Windows Form projects from new developers just starting out to quickly building internal utility projects.

In this article learn how to show images from a project’s resources in a windows form working with .NET Core 7 Window Forms and a .NET Core 7 class project (optional).


![sample display](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0f1zdg73pmui9vm6858w.png)

## Source code

Clone the following [GitHub repository](https://github.com/karenpayneoregon/winforms-embed-resources).

> **Note**
> I've seen this question pop-up on various forms over the past 20 years and this is one reason for this article.

## Let's begin

Although the code could be completely written in a single form which means to use said code in another project the developer must pick through the code, copy and paste into another project. There is a project done this way while another project uses a class project for base code to read images from the calling project resources.

Feel free to examine code for the project `ChangeImage` were all need code is in the project.

We will focus on using a class project, `ResourceLibrary`.

The model for storing resource information.

```csharp
public class ResourceItem
{
    /// <summary>
    /// Resource name
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// Image which is either an <see cref="Icon"/> or <see cref="Bitmap"/>
    /// </summary>
    public Bitmap Image { get; set; }
    /// <summary>
    /// Indicates if dealing with an icon so when displaying the
    /// control used to display can adjust it's size or Size mode
    /// </summary>
    public bool IsIcon { get; set; }
    public override string ToString() => Name;
}
```

The following class reads images of type `Icon` and `Bitmap`

```csharp
using System.Collections;
using System.Drawing;
using System.Globalization;
using System.Resources;
using ResourceLibrary.Models;

namespace ResourceLibrary;

public class ImageHelper
{
    public static List<string> ResourceImageNames(ResourceManager manager)
    {

        var names = new List<string>();
        var resourceSet = manager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);

        names.AddRange(resourceSet!.Cast<DictionaryEntry>()
            .Where(dictionaryEntry => dictionaryEntry.Value is Image || 
                                      dictionaryEntry.Value is Icon)
            .Select(dictionaryEntry => dictionaryEntry.Key.ToString()));

        return names;
    }


    /// <summary>
    /// Get all bitmap and icon resources
    /// </summary>
    /// <returns></returns>
    public static List<ResourceItem> ResourceItemList(ResourceManager manager)
    {
        var items = new List<ResourceItem>();

        foreach (var name in ResourceImageNames(manager))
        {

            var item = new ResourceItem()
            {
                Name = name, 
                IsIcon = false
            };

            if (manager!.GetObject(name) is Icon)
            {
                item.Image = ((Icon)manager.GetObject(name)!)?.ToBitmap();
                item.IsIcon = true;
            }
            else
            {
                item.Image = (Bitmap)manager.GetObject(name)!;
            }

            items.Add(item);

        }

        return items;

    }
}

```

Next, several language extensions which filter all resource list to a specific type.

```csharp
public static class ResourceItemExtensions
{
    /// <summary>
    /// Return resources of type Icon
    /// </summary>
    /// <param name="sender"></param>
    /// <returns>list of icons or an empty list</returns>
    public static List<ResourceItem> Icons(this List<ResourceItem> sender) 
        => sender.Where(item => item.IsIcon).ToList();

    /// <summary>
    /// Return resources of type Bitmap
    /// </summary>
    /// <param name="sender"></param>
    /// <returns>list of bitmaps or an empty list</returns>        
    public static List<ResourceItem> BitMaps(this List<ResourceItem> sender) 
        => sender.Where(item => !item.IsIcon).ToList();
}
```

In a forms project, add a ListBox and PictureBox with the PictureBox large enough to all all images to be displayed. Later in code there is a method to adjust the PictureBox SizeMode.

Add a reference to the class project.

Add the following class which can be used in other projects.

```csharp
public sealed class ResourceImages
{
    private static readonly Lazy<ResourceImages> Lazy 
        = new(() => new());

    public static ResourceImages Instance => Lazy.Value;

    private List<ResourceItem>? _images;
    /// <summary>
    /// Get all icon and bitmap images from project resources
    /// </summary>
    /// <returns>list of images</returns>
    public List<ResourceItem> Images()
    {
        _images = ImageHelper.ResourceItemList(
            Properties.Resources.ResourceManager);
        return _images;
    }
}
```

To display all images, add a BindingSource to the form.

```csharp
private readonly BindingSource _allBindingSource = new ();
```

In Form OnShown event, add the following code to get all images.

```csharp
_allBindingSource.DataSource = ResourceImages.Instance
    .Images()
    .OrderBy(x => x.Name)
    .ToList();
```

Add the following method to the form for displaying the current image when the user changes the selected item in the ListBox.

```csharp
private void ChangeFromAllImage()
{
    if (AllImagesListBox.SelectedIndex <= -1) return;

    var item = (ResourceItem) _allBindingSource.Current;
    AllImagesPictureBox.SizeMode = item!.IsIcon ? PictureBoxSizeMode.Normal : PictureBoxSizeMode.Zoom;
    AllImagesPictureBox.Image = item.Image;
}
```

And,

```csharp
private void BitmapBindingSource_PositionChanged(object? sender, EventArgs e)
{
    ChangeFromBitmapImage();
}
```

Back to OnShown event, add the following lines which 

- Displays the image names in the ListBox as `ResourceItem` overrides ToString which the ListBox uses for DisplayMember.

- Subscribes to OnPosition changed which called ChangeFromAlImages which in turn displays the appropriate image.

```csharp
        AllImagesListBox.DataSource = _allBindingSource;
        _allBindingSource.PositionChanged += AllBindingSource_PositionChanged;

        ChangeFromAllImage();
```

**Caveat**

Suppose there is a need to display a specific image? Although a BindingSource has a Find method, it is not supported for a list. The work around is to use a BindingList which is populated with the images via 

```csharp
_bindingList = new BindingList<ResourceItem>(ResourceImages.Instance
    .Images()
    .BitMaps()
    .OrderBy(x => x.Name)
    .ToList());
```

Setup as before but with the BindingList

```csharp
_bitmapBindingSource.DataSource = _bindingList;
BitmapImagesListBox.DataSource = _bitmapBindingSource;
```

Now to find a specific image.

```csharp
var resourceItem =_bindingList.FirstOrDefault(x => x.Name == "Miata2");
if (resourceItem != null) _bitmapBindingSource.Position = 
    _bitmapBindingSource.IndexOf(resourceItem);
```