How to find the elusive ToolboxBitmap icon
When you create your own Windows Forms controls you can add a bitmap that will be seen on the toolbox menu as shown in figure 1.
Figure 1. Custom toolbox bitmaps.
This is accomplished using the ToolboxBitmap attribute on your control or component based class to nominate a bitmap. The preferable method for distributing the bitmap is in the resources of the assembly containing the control. This bitmap should be added to the solution and marked as an embedded resource.
Finding the bitmap can be confusing however because the resource can only be found if you know the fully qualified name of the bitmap image. Ascertaining that fully qualified path is simple if you know the formula.
A common mistake is that the name should be prefixed with the assembly name such as "/upload/20141122/1416604105342.bmp". This is not necessarily the case. The fully qualified path depends on a couple of factors. First, the default namespace of the assembly and second, whether the resource is stored in folders in the solution.
If the default namespace of the assembly has been changed from the original settings you will need to prepend that and if the resource is stored in any folder tree below the solution you'll need to prepend the all in order also. Finally, the exact spelling of all the namespaces, folders and resources is important so you need to make sure that the whole thing is spelled exactly. Figure 2 shows a solution with some embedded bitmaps.
Figure 2. A simple solution
The default namespace of this control project is "ToolboxIconDemo" and the names of the resources are:
Changing the default namespace to "Foo" renders the following results:
Obviously, changing the default namespace to a blank string will shorten the resource names and picking a more complex namespace such as xRay.Toolkit.Controls will make it correspondingly longer.
However, that's not the whole story. In order to use the bitmaps as icons in the toolbox the ToolboxBitmap attribute needs to find them in the context of their own namespace. The ToolboxBitmap attribute requires a type or string type name to locate the bitmap. The form of the ToolboxBitmapAttribute constructor is:
The ones interesting to this discussion are the first and second constructors because the third gets the image from a file on the hard-disk. The constructors are very sensitive to namespace names and can cause problems if you require that your objects reside in namespaces different to that provided by default. If your default namespace and assembly name are the same then the formula is fairly simple. You can name your bitmaps arbitrarily and use the first constructor to find them so long as you use the fully qualified default namespace followed by the resource name such as; [ToolboxBitmap(typeof(MyControl),"/upload/20141122/1416604105345.bmp")] Alternatively, you can name the resource to be the same as the control and use the second constructor such as; [ToolboxBitmap(typeof(MyControl)] and the bitmap will be called "/upload/20141122/1416604105346.bmp"
If however you require an assembly name that is different to the default namespace such as an asembly called "Foo.dll" and a namespace of "My.Imaginary.Corporate.Namespace", which is not an unlikely scenario, you're going to be out of luck because a bug in the GetImageFromResource method prepends the name of the assembly and makes a resource string such as "MyControl./upload/20141122/1416604105345.bmp" which won't ever exist in the assembly.
To overcome this problem and to simplify the process of finding the resource you can do the following:
#1 Create an internal class called "resfinder" outside of the root namespace of your source code.
#2 Use "resfinder" in the toolbox bitmap attribute instead of your control name.
#3 use the "
The code looks a bit like this, the default namespace is "Foo":
internal class resfinder
/// Summary description for UserControl1.
public class UserControl1 : System.Windows.Forms.UserControl
This locates the toolbox bitmap every time.
If you're not really sure of the resource namespaces you can do the following little trick to find them. I don't suggest leaving this in but you can run this code once in debug mode and take it out when you know the names. In the constructor of your control do the following:
// This call is required by the Windows.Forms Form Designer.
// TODO: remove the following lines after you know the resource names
foreach(string s in sa)