Introduction

Have you ever wanted to get rid of that ugly Windows scrollbar? I know I have many many times. Until now, it has been an extremely tedious and difficult task. Back in the days before .NET, it was a huge undertaking to get rid of the default scrollbars for listviews, list control, and any other control that has the default Windows scrollbar. If you want to see just how difficult it is, check out my other article I wrote for Visual C++ 6.0 MFC, How to Skin CListCtrl including scrollbars and column headers.

Fortunately for us, we now have user controls and panels in the .NET framework. This simplifies things a lot, but it's still not easy or straightforward to customize the look and feel of Windows scrollbars and have them work properly.

Getting Started

First thing we will do is create a new C# Windows Application project called TestApp. Open Form1.cs in Design mode, and add a Panel control that is 179 pixels in height, and name it outerPanel. Then, create another Panel, but this time create it inside the OuterPanel, and name it InnerPanel. Now, set the innerPanel's AutoScroll property to True.

Next, we want to throw some kind of a control into the innerPanel so that we will have the ability to scroll in order to test our custom scrollbar. For some reason, we can not use the design editor to add a control to the innerPanel, because it messes up the DisplayRectangle property and does not return the correct value. So what we have to do is add the control to the innerPanel using code, and then everything will work fine.

So, open up Form.cs in View Code mode, and just under the InitializeCompontent(); call, insert the following code:

This will add a button 900 pixels down from the top of the innerPanel, and we should have a scrollbar showing up when we run the application.

Skinning the Scrollbar (If only it were that simple :p)

Now, we have a Panel that will scroll, but it's ugly. So, how do we skin it? Well, there is actually no way to skin a Windows scrollbar, as far as I know. So what we have to do is create our own scrollbar as a user control. Basically, we have to mimic exactly what the Windows VScroll control does, but add the ability to be able to use graphics for the arrows, channel, and thumb tracking controls. Then, later on, we will write some more code that will enable us to hide the panel scrollbar, as well as make our custom user control scrollbar, control the panel's scrolling.

We start by adding a new Control Library Project to our solution, and we will rename the User Control that it adds by default, to CustomScrollbar.

Now, we start creating graphics and writing code to make our CustomScrollbar look and function the way we would like it to.

Creating the Scrollbar Graphics

So first, we have to figure out how to create graphics in a fashion that lends itself to being reusable in most instances. I know that a scrollbar always has four common properties:

Up arrow

Down arrow

Thumb control

Channel

This is cool, so we just need the ability to be able to supply an up arrow graphic, down arrow graphic, thumb control graphic, and a channel graphic/color.

However, there is one more thing.... The thumb control for a standard Windows scrollbar always sizes appropriately depending on the Minimum/Maximum and LargeChange properties. This means that we have to give our thumb control the ability to change its size dynamically. Yes, this is not fun, because in order to do this using graphics, we have to split up our thumb control graphic into five different graphics, two of which will need to be spanned accordingly to how big our thumb control is supposed to be. Here is how I cut up my graphics:

So as you can see, we will have the following graphics which we will allow to be customized through the Properties panel on the user control.

Up arrow image

Down arrow image

Thumb top image

Thumb top span image

Thumb middle image

Thumb bottom span image

Thumb bottom image

For this implementation, I will implement the channel portion as a solid color rather than as a graphic, just for demonstration. It's easy enough to change it to use an image if you like. Incidentally, it is also very easy to add the ability to have mouseover images for the arrows and thumb controls, but I won't be covering that. I will leave that as an exercise for all you developers out there :)

Preparing the properties and events for the scrollbar control

Now, we have our graphics all figured out. We just have to determine how we want our scrollbar to function. I don't like re-inventing the wheel or changing the things that I am used to. So, I am going to make our custom scrollbar work exactly like the VScroll or Windows scrollbar control, so that if I want to use my custom scrollbar in place of an ugly Windows scrollbar, I can just simply swap them out and it will work.

Therefore, my control will have the following properties exposed:

Maximum - int

Minimum - int

Value - int

LargeChange - int

SmallChange - int

and the following events:

Scroll

ValueChanged

and the following custom properties to facilitate our ability to skin:

ChannelColor - Color

DownArrowImage - Image

ThumbBottomImage - Image

ThumbBottomSpanImage - Image

ThumbMiddleImage - Image

ThumbTopImage - Image

ThumbTopSpanImage - Image

UpArrowImage - Image

With all of these properties implemented properly in a user control, we will have ourselves a completely customizable scrollbar that will function exactly as a regular Windows scrollbar, but it will also have the ability to look as cool or uncool as we would like it :)

Implementing the Scrollbar User Control

Now, here is the tough part. We have to program our very own scrollbar control. This is not necessarily an easy task to accomplish. However, once you are done making this work, you should never have to code another one ever again, and if you do, at least you will have a code base to start from with what we have developed here.

In order to make our custom scrollbar, we will need to override and/or respond to the following events:

OnPaint - override

MouseUp - handle

MouseDown - handle

MouseMove - handle

First, we will instantiate all of our variables. Some are protected, and will later be exposed, and some are private for internal use only.

Now that we have all our of variables setup, we need to expose a bunch of them as properties, so that developers that are using the scrollbar control can access and modify the properties at design time.

Now we have to write all the code to handle when a user clicks the up or down arrows, and the most difficult part, write the code to move the thumb control when the user clicks and drags the thumb portion of the control.

Now we are done writing the scrollbar user control. Keep in mind, I have left certain things out that are not that important. So please see the source code accompanied with this article. Now, we just need to the hide the default scrollbar on the panel, and hook up our custom scrollbar.

Hide the Default Scrollbar and Hook Up our Custom Scrollbar

So now, we have to add our custom scrollbar to our form, beside our Panels. So first, build our solution. Now, let's right click on our toobox and click "Choose Items..." and browse to the CustomControls.dll and add our CustomScrollbar to the toolbox.

Next, add an instance of our CustomScrollbar to the form beside the Panel. Now, we will add the code to hook up the CustomScrollbar so that it will scroll our panel that we setup.

Add the code shown heren just below the code that we added earlier to create the button, below the InitializeCompontent() function:

Now, the only thing left is to hide the default scroll bar that the Panel brings up. Well, that's actually very easy now, thanks to Panels. Remember the outerPanel that we created? Well, all we have to do is decrease the width of the outerPanel so that it hides the innerPanel scrollbar, and that's it.

Conclusion

So now, our custom scrollbar will scroll our Panel just as the regular scrollbar does. Only now are we able to change the look and feel of our scrollbar whenever we want. I did skip over some small details in the creation of this control, but all the code is available in the source code package above.

Some things to improve are as follows:

Add ability to support mouse rollover images for the up and down arrows and the thumb control.

Add ability to hold the mouse button down on arrows and have the control continually scroll.

Add ability to click the channel portion of the scrollbar and have it scroll the amount of the LargeChange property.

This article has been very helpful. However, if we place the child control (i.e. Button) of the inner panel at a location that is 20 times greater than the height of the inner panel, the custom scroll does not work properly.

You can check it out by carrying out the following change File: form1.cs Line: 19 Change: "b.Location = new Point(0, 20 * this.innerPanel.Height);"

First off I want to congradulate on the code. Looks Good and does not run slow or flicker.

I see how you using it in panels but is there any way to implement this into the treeview. All I see in the control is a Scrollable property which is a bool and there is an AutoScrollOffset Which does nothing for me.

It's also possible to replace the scroll bar entirely with one large up button and one large down button. This will do the same thing if you program the buttons to select one row either way at a time and multiple if the user holds down the button. This helps our fat fingered friends that use touch screens.

I have a flowlayout panel where i am adding some controls.I have set autoscroll property of my flowlayout panel to true.When the controls in the flowlayout panel exceeds its width, then scrollbar appears but the last control in the flowlayout panel overlaps with the scrollbar...Is there any solution to this problem...RegardsVarun...

Hi, Thanks for such a nice control. I am facing a scenario. In panel I have multiple list views and this list views allow drag drop. Now on drag drop I want to scroll the panel based on the current cursor position. Please help me out.