A number of controls within .NETCF have built in ScrollBars. Occasionally you may
want to operate these programmatically on behalf of the user. When you do this you
want both the control to scroll and the scrollbars to correctly reflect the current
position. Faced with this requirement I found a solution in the WM_VSCROLL (and equivalent
HSCROLL) message. You can send this message to the native handle of your control along
with a number of present constants to offer hands-free scrolling. Along the way I
discovered that to work you must have the handle of the native control which implements
the scroll bars. In the case of the WebBrowser this is a grand-child of the outer
managed control so we have to use the native GetWindow API call to get down to the
right HWND. I wrapped this up in a class I've called ScrollBarHelper which allows
the user to move left, right, up and down. The code for the class is:-
///
<summary>
///
Helper class to programmatically operate scrollbars.
///
</summary>
public
class ScrollBarHelper
{
private IntPtr handle;
public ScrollBarHelper(Control c)
{
if (c is WebBrowser)
{
//special case for complex control
//get the inner IE control
IntPtr hInternetExplorer = NativeMethods.GetWindow(c.Handle,
NativeMethods.GW.CHILD);
//get the first child (status bar)
IntPtr hStatus = NativeMethods.GetWindow(hInternetExplorer,
NativeMethods.GW.CHILD);
//get the html body area
handle = NativeMethods.GetWindow(hStatus,
NativeMethods.GW.HWNDNEXT);
}
else
{
handle = c.Handle;
}
}
publicvoid LineRight()
{
SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_LINEDOWN);
}
publicvoid LineLeft()
{
SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_LINEUP);
}
publicvoid PageRight()
{
SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_PAGEDOWN);
}
publicvoid PageLeft()
{
SendMessage(NativeMethods.WM_HSCROLL, NativeMethods.SB_PAGEUP);
}
publicvoid LineDown()
{
SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_LINEDOWN);
}
publicvoid LineUp()
{
SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_LINEUP);
}
publicvoid PageDown()
{
SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_PAGEDOWN);
}
publicvoid PageUp()
{
SendMessage(NativeMethods.WM_VSCROLL, NativeMethods.SB_PAGEUP);
}
privatevoid SendMessage(int msg, int value)
{
Microsoft.WindowsCE.Forms.Message m = Microsoft.WindowsCE.Forms.Message.Create(handle,
msg, (IntPtr)value, handle);
Microsoft.WindowsCE.Forms.MessageWindow.PostMessage(ref m);
}
[DllImport("coredll.dll")]
internalstaticextern IntPtr
GetWindow(IntPtr hWnd, GW uCmd);
internalenum GW
: int
{
HWNDFIRST = 0,
HWNDLAST = 1,
HWNDNEXT = 2,
HWNDPREV = 3,
OWNER = 4,
CHILD = 5,
}
//scrollbar
messages
internalconstint WM_HSCROLL = 0x0114;
internalconstint WM_VSCROLL = 0x0115;
//constants
for scrollbar actions
internalconstint SB_LINEUP = 0;
internalconstint SB_LINEDOWN = 1;
internalconstint SB_PAGEUP = 2;
internalconstint SB_PAGEDOWN = 3;
}
In order to use the control you create a new instance passing it the control of your
choice. Then call methods to scroll the control e.g.
private ScrollBarHelper
wsbh;
private ScrollBarHelper
tsbh;
privatevoid Form1_Load(object sender,
EventArgs e)
{
wsbh =new ScrollBarHelper(webBrowser1);
tsbh =new ScrollBarHelper(textBox1);
}
private
void button1_Click(object sender,
EventArgs e)
{
tsbh.PageUp();
}
The control contains methods to Scroll via single lines or pages at a time, I didn't
get around to looking at setting the explicit value of the scrollbar control, but
this should be possible also - refer to the documentation for WM_VSCROLL for
how to pass the value.