.NET Control C++/CLI Treasures - Toolbox Bitmaps

One of the most frustrating things I have encountered whilst developing C++/CLI controls is getting a simple ToolboxBitmap to work correctly! Yes, it’s ironic I know, to find that one of the first things (or the very last thing) that you need to do as a control developer is to get your graphic artist to design an icon for your control and then allow it to be displayed in the Visual Studio Toolbox like a normal control (like a Button, ComboBox or DataGridView, for example).

If we were developing in VB.NET or C#, we find that this is a simple task. Unfortunately, in C++/CLI the process is awkward and there is nothing anywhere that describes how it is done. Several developers on the web have also encountered this issue with no appropriate responses.

In a nutshell, Microsoft suggests the form:

[ToolboxBitmap(MyControl::typeid, "MyControl.bmp")]
public ref class MyControl : public Control {
...
};

…and specifies that the “BuildAction property set to EmbeddedResource“. This is of course a bogus comment for a C++ project which has no such property of a bitmap.
C++ developers would then naturally starting thinking of a Resource File (.rc) and include the image in that.

After struggling with that route, a C++ developer might also try using an Assembly Resource File (.resx). Again, developers will quickly fall flat on their face with a profound lack of progress.

So without further ado, here’s what you need to do to get your ToolboxBitmapAttribute working correctly in C++/CLI.

Embedding an Image in C++/CLI

Assuming you have a control in a nested namespace :

namespace MyCompany { namespace MyControls {
public ref class MyControl : public Control
{
...
};
}} // namepace MyCompany::MyControls

You have two options to get your image working correctly:

  1. Use your nested Namespace and name your bitmap “MyCompany.MyControls.MyControl.bmp”
  2. Use a Global Namespace helper and name your bitmap “MyControl.bmp”

Using a nested Namespace

  1. You will need to create your 16×16 image and save it with the fully qualified namespace, eg “MyCompany.MyControls.MyControl.bmp”
  2. Add it to your project (No, you don’t need to add it to a Resource (.rc) or Assembly Resource (.resx) file.
  3. Add the attribute [ToolboxBitmap(MyControl::typeid, “MyCompany.MyControls.MyControl.bmp”)]
  4. Go to Project Settings -> Linker -> Input and addMyCompany.MyControls.MyControl.bmp to “Embed Managed Resource File”
  5. Voila! Just build and test your icon (see some notes below)

Your code should look like the following:

namespace MyCompany { namespace MyControls {
[ToolboxBitmap(MyControl::typeid, "MyCompany.MyControls.MyControl.bmp")]
public ref class MyControl : public Control
{
...
};
}} // namepace MyCompany::MyControls

Using the Global Namespace

This was an idea I found from a C# developer who recommeded using a Global Namespace idea. This means that you can simply name your bitmaps logically (eg “MyControl.bmp”). See here for the article.

  1. In your stdafx.h (or some other central location), add a simple internal class that exists in the global namespace, eg: ref class resloader { };
  2. You will need to create your 16×16 image and save it, eg “MyControl.bmp”
  3. Add it to your project (No, you don’t need to add it to a Resource (.rc) or Assembly Resource (.resx) file.
  4. Add the attribute [ToolboxBitmap(resloader::typeid, “MyControl.bmp”)]
  5. Go to Project Settings -> Linker -> Input and add MyControl.bmpto “Embed Managed Resource File”
  6. Voila! Just build and test your icon (see some notes below)

Your code should look like the following:

ref class resloader { };
namespace MyCompany { namespace MyControls {
[ToolboxBitmap(resloader::typeid, "MyControl.bmp")]
public ref class MyControl : public Control
{
...
};
}} // namepace MyCompany::MyControls

A Quick Note

  • When testing your image, I found that your toolbox image may not update immediately. The easiest workaround was to have a second copy of Visual Studio open and then simply begin to add your DLL to the Toolbox in the 2nd VStudio (Choose Items… -> Browse… ->). Then move up/down to your control and see if the icon is displayed correctly in the ‘Choose Toolbox Items’ dialog. If you see the default icon, it’s not working. PS: ALWAYS hit cancel otherwise you’ll need to shutdown and re-open your 2nd copy of VStudio, because it appears to cache your image.
  • You can use other image types other than a Bitmap (eg an Icon). Note that the other image types may look ugly though.

Happy Coding!

References

Thanks go to the following to the developers who gave me the hints needed to find the solution:

blog comments powered by Disqus