Introduction
Working on a project for different Windows Mobile/CE/PocketPC devices, I needed to support different screens. I encountered a problem when I had to support a device with a 2.5" screen which had to be used with a finger (no pen). The default scroll bar width in Windows Mobile is 13 px which is definitely too small to hit using your finger on such a small display. This article shows a workaround to make only specific scroll bars wider in your application without changing the standard width for the OS.
Background
The .NET Framework is very powerful and gives you a lot of functionalities out of the box. This makes it even more annoying when you come across a simple functionality that is not only not available in the .NET Framework but also very difficult to handle using PInvoke or other similar methods.
Setting the width of the scroll bar in a simple panel is one of these simple functionalities. The .NET Framework has a class for vertical scroll bars (VScrollBar
) and it shows a scroll bar on the scrollable controls like panel. However you have no access to their scroll bar in any way. I Googled the topic and found several suggestions, all of them having at least one disadvantage:
- Change the scroll bars of the whole OS by changing the registry: needs a reboot, changes all applications and all scroll bars in them
- Write your own container controls: unpleasant and needs to implement existing functionality
- Use reflection to find a
private
member of the scrollable control which represents the scroll bar: unfortunately does not work on Windows Mobile
So I started thinking how I can use the standard VScrollBar
control to overlap and mimic the functionality of the standard scroll bar. In one of my searches, I came across Peter Foot's article on scrolling controls which was a good start: it presented a way to programmatically scroll the control. So my first idea was to configure my scroll bar in the same way as the standard one and scroll it using this code. This worked only partially because I could not guess the formulas Microsoft uses to determine the min and max values of the scroll bar as well as their steps (line step and page step). Also there was no way to jump to a specific location, only to jump a "line" or a "page".
Using some PInvoke methods, I succeeded in getting the min and max values of the original scroll control as well as the page step. The line step is not available in the scroll info so I just "guessed" it to be 3 px for panels and set that as a constant.
Now the only thing left was to scroll the standard bar to the same position as mine whenever the user changed it. Initially I tried jumping some pages and some lines to get as close to the needed position as needed. This was however clumsy, slow and inaccurate. So I came up with another idea: change the page step of the original scroll control, jump a page and restore the page step. Easier said than done because Microsoft seems to care about any changes you post using SetScrollInfo
only after all events have been processed. I succeeded to go around this by calling Application.DoEvents()
after setting the scroll info and I got good results.
The final step was to pack all this in an extension method which is convenient to use. This was the easiest part.
Using the Code
To use the code, follow these steps:
- Add the file ScrollBarHelperEx.cs to your project
- Add a reference to
Microsoft.Windowsce.Forms
to your project
- Add a
using
clause using IESoft;
to the form with the panel
- Set the
AutoScroll
property of your panel to true
- Add all controls to the panel
- Call the method
SetVScrollBarWidth
of the panel with a single parameter the new scroll bar width in pixels
for (int i = 0; i < 8; i++)
{
var b1 = new Button();
b1.Text = "Button " + i;
b1.Width = this.label1.Width;
b1.Location = new Point(this.label1.Left, this.label1.Bottom +
i * b1.Height + (i + 1) * 5);
this.panel1.Controls.Add(b1);
var b2 = new Button();
b2.Text = "Button " + i;
b2.Width = this.label2.Width;
b2.Location = new Point(this.label2.Left, this.label2.Bottom +
i * b2.Height + (i + 2) * 5);
this.panel2.Controls.Add(b2);
}
this.panel2.SetVScrollBarWidth(40);
Points of Interest
I really don't understand why Microsoft does not provide us the possibility to handle such simple tasks directly or indirectly. I've used a lot of solutions for such problems coming from CodeProject and I hope to help some other people with this article.
Known Issues and Possible Enhancements
I found several issues in my solution:
- When scrolling fast up and down, sometimes the scroll bars get desynchronized. A successive scroll usually fixes the problem.
- If you set the width of the scroll bar before adding all controls, the custom scroll bar will not be correct. This can be easily fixed by resetting the custom scroll bar but I did not add this functionality as I don't need it.
There are several possible enhancements I could think of:
- Add the same functionality for setting the height of the horizontal scroll bar. Having the ready code this is pretty easy and straightforward.
History
- First version created on May 10th, 2010