Recently in Windows Forms Category

In my previous entry, "Using ToolStripControlHost with a Trackbar", I noted that the problem with this method resulted in the ToolStripTrackBar looking unlike anything else on the ToolStrip when it was in ManagerRenderMode. This has driven me nuts during the preceding week. Here are some of the steps that I took to solve this problem, all of which failed:

Tried to set Backcolor on ToolStripTrackBar: no effect.
Override OnPaint method with ToolStripTrackBar: no effect.
Derive MyTrackBar from TrackBar, override OnPaintBackground, put MyTrackBar in ToolStripControlHost: color, but no trackbar!

The latter step failed because TrackBar is one of those .NET controls that wants to perform all the drawing--if you override OnPaint, it won't be called unless you call SetStyle, as Tom Holt described in this CodeProject article:

// this call says "I'll draw it myself"
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint, true);

From what I read on various message boards, no one had my specific problem (needing a TrackBar on a ToolStrip), but plenty of people had a situation where they wanted the TrackBar to be transparent on a Form that contained a bitmap image or specific visual style. I could see that type of TrackBar being useful and potentially the key to solving this problem, and I found a great article from Bob Powell showing how to create a transparent C# control. After finding this MSDN article with sample code for the TrackBarRenderer class, I decided to create my own control: CrystalTrackBar.

CrystalTrackBar
CrystalTrackBar has two different modes you can set. One is "TransparencyMode", which allows the background of the Form to show through, as it does with the second control in this screenshot. I then proceeded to take the CrystalTrackBar, and wrap it in a ToolStripControlHost to create CrystalToolStripTrackBar. The transparency mode allows the finely rendered background of the ToolStrip to show through, creating a seemless effect. As a bonus, I created a second mode that works when TransparencyMode is set to false--a gradient effect is created, as in the first control within the form. You can set Color1, Color2, and the angle of the gradient.

I'll be sharing the code soon. CrystalTrackBar isn't yet as feature rich as the TrackBar and I want to include some additional modes. I've got a small painting bug when I move the thumb around, but I may release it in the hopes that someone will suggest a better way of doing things.

I'm currently developing an application that displays images (bmp, jpg, etc) in a Windows Forms application. The application can scale the image within a panel, making it fit, or allowing an interactive scale. To enhance this functionality, I wanted to include a slider Trackbar control to my toolstrip. The end result needed to look like this:

trackbar on toolstrip

Fortunately, this is easily accomplished with .NET 2.0, by using the ToolStripControlHost class to wrap controls for the ToolStrip. I was even able to find code that specifically added the Trackbar on WindowsForms.net. All I had to do was place this code inside a file called ToolStripTrackBar.cs (see the link to this below), add a few using clauses to bring in the required assemblies, and it compiled just fine. Now what? I spent a good period of time just trying to find TrackBar in the Visual Studio Toolbox. At first I thought it might show up where the user controls are located, under the first control group with the name of your program. Nothing new there. Nada for the "All Windows Forms" control group. I couldn't find it anywhere. Compiled again, exited and restarted Visual Studio. Nada. I decided to give up and decided to add some buttons to my toolstrip. Voila! On the bottom of the menu that allows you to add toolstrip items, the Trackbar item had wonderfully appeared!

trackbar on toolstrip menu

It's all very easy and automatic, however none of the references to this specific example told me where to find the Trackbar. The benefits of having the Trackbar in Visual Studio designer are great, as you can visually position and resize the control. However, the Properties settings for the trackbar object, embedded in the ToolStripControlHost, were not persistent. I had to write a method to intialize the trackbar object:

private void InitTrackBar()
{
    zoomToolStripTrackBar.TrackBar.TickStyle = 
        TickStyle.None;
    zoomToolStripTrackBar.TrackBar.BackColor = 
        this.toolStrip1.BackColor;
    zoomToolStripTrackBar.TrackBar.Scroll += 
        new EventHandler(this.scrollZoom_Scroll);
    zoomToolStripTrackBar.TrackBar.Value = 5;
}

That was problem #1. Problem #2 was that while the ToolStrip was set to ManagerRenderMode, this property does not automatically extend to the ToolStripControlHost. If you look at my first picture, you'll notice that the TrackBar is grey while the rest of the ToolStrip is blue. If I figure out the reason for this, I'll record it here.

Link:
ToolStripTrackBar.cs

How do you access resource files (bmp, mp3, etc) that are compiled into your Windows Forms executable? After googling the subject, the Assembly object's GetManifestResourceStream method seemed to be the solution. MSDN's entry on this subject makes it seem relatively simple. However, it took me over an hour to get it to work in my latest project. There are two things you must do in other to access an executable's resources:

  1. You must know the exact name of resource (mynamespace.resource.resourcename).

  2. You must embed the resource into your executable.

Accessing the resources means that you must have access to the executable's Assembly object. I cached this in the Form's Load event:

Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();

The image file that I was trying to access in my program was called Image1.bmp. I made a call to GetManifestResourceSteam like this:

imageStream = _assembly.GetManifestResourceStream(
    "ThumbnailPictureViewer.Image1.bmp");

The problem was that _imageStream was always returning NULL. Digging a little further, various articles mentioned that my decorated name might be incorrect. Perhaps I was using the wrong namespace, or the case sensitive name might be wrong? The only way to determine this was to use GetManifestResourceNames(). You can retrieve a collection of string resource names and dump them out to the console:

string[] names = _assembly.GetManifestResourceNames();
foreach (string name in names)
    System.Console.WriteLine(name);

The console showed me a few resource namespaces, but no embedded objects! Even had Image1.bmp clearly in my Solution Explorer, and in my Project properties, Resources tab, it never showed up. The trick in getting this to work is to make certain that Image1.bmp was set to Embedded Resource in the Properties window:

Build Action should be set to Embedded Resource

When you create resources in Visual Studio 2005, they are linked to your executable by default at compile time. This is a nice option if you want to keep the resource files separate from the .resx file, allowing other people to change them. If it needs to be accessed programatically with GetManifestResourceStream, it has to be Embedded into the .resx file. The only drawback here is that my Image resource can only be changed within Visual Studio 2005. Once I changed the Build Action to Embedded, I saw the correct name in the output window:

ThumbnailPictureViewer.resources.Image1.bmp

And then my code to load Image1.bmp into a Bitmap object worked successfully:

Stream _imageStream;
_imageStream = 
    _assembly.GetManifestResourceStream(
    "ThumbnailPictureViewer.resources.Image1.bmp");
Bitmap theDefaultImage = new Bitmap(_imageStream);

External Link:
MSDN summary on Linked vs. Embedded resources.

Previous 1 2