Share via


UltraNav Scroll Helper

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class UltraNavScrollHelper:Component
{
private Control _hScrollBar;
private Control _vScrollBar;
private Control _controlSite;
private NativeScrollBar _nsb;
private NativeWndProcListner _npl;
private bool _created;

    public UltraNavScrollHelper(IContainer container) {
container.Add(this);
}

    public UltraNavScrollHelper(Control control, Control horizontalScrollBar, Control verticalScrollBar)
{
this.Control = control;
this.HorizontalScrollBar = horizontalScrollBar;
this.VerticalScrollBar = verticalScrollBar;
}

    protected override void Dispose(bool disposing)
{
if (_controlSite != null)
{
_controlSite.HandleCreated -= new EventHandler(_controlSite_HandleCreated);
_controlSite.HandleDestroyed -= new EventHandler(_controlSite_HandleDestroyed);
_controlSite = null;
DestroyHandle();
}

        base.Dispose(disposing);
}

    public Control Control
{
get { return _controlSite; }
set
{
if (value != null && value != _controlSite)
{
_controlSite = value;
_controlSite.HandleCreated += new EventHandler(_controlSite_HandleCreated);
_controlSite.HandleDestroyed += new EventHandler(_controlSite_HandleDestroyed);
}
}
}

    public Control HorizontalScrollBar
{
get { return _hScrollBar; }
set
{
_hScrollBar = value;
CreateHandle();
}
}

    public Control VerticalScrollBar
{
get { return _vScrollBar; }
set
{
_vScrollBar = value;
CreateHandle();
}
}

    private void CreateHandle()
{
if (_created) return;

        if ((this.Site == null || this.DesignMode == false) && (this._vScrollBar != null || this._hScrollBar != null))
{
this._nsb = new NativeScrollBar(_controlSite);
this._npl = new NativeWndProcListner(this, _controlSite);
_created = true;
}
}
private void DestroyHandle()
{
if (this._nsb != null)
{
this._nsb.DestroyHandle();
this._npl.DestroyHandle();
_created = false;
}
}

    private void _controlSite_HandleCreated(object sender, EventArgs e)
{
CreateHandle();
}

    private void _controlSite_HandleDestroyed(object sender, EventArgs e)
{
DestroyHandle();
}

    internal class NativeWndProcListner : NativeWindow
{
private Control _toListen;
private UltraNavScrollHelper _owner;

        private const int WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115;

        private class ControlHelper : Control
{
internal static void ReflectMessageHelper(IntPtr hWnd, ref Message m)
{
Control.ReflectMessage(hWnd, ref m);
}
}

        public NativeWndProcListner(UltraNavScrollHelper owner, Control toListenTo)
{
_toListen = toListenTo;
_owner = owner;
if (_toListen.IsHandleCreated)
{
this.AssignHandle(_toListen.Handle);
}
}

        protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_VSCROLL:
if (_owner.VerticalScrollBar != null &&
m.LParam != _owner.VerticalScrollBar.Handle
&& _owner.VerticalScrollBar.Visible)
{
ControlHelper.ReflectMessageHelper(_owner.VerticalScrollBar.Handle, ref m);
}
break;
case WM_HSCROLL:
if (_owner.HorizontalScrollBar != null &&
m.LParam != _owner.HorizontalScrollBar.Handle
&& _owner.HorizontalScrollBar.Visible)
{
ControlHelper.ReflectMessageHelper(_owner.HorizontalScrollBar.Handle, ref m);
}
break;
}

            base.WndProc(ref m);
}
}
internal class NativeScrollBar : NativeWindow
{
public NativeScrollBar(Control parent)
{

            CreateParams cp = new CreateParams();

            // Fill in the CreateParams details.
cp.Caption = String.Empty;
cp.ClassName = "SCROLLBAR";

            // Set the position of the scrollbar so that it is offscreen
cp.X = -1000;
cp.Y = -1000;
cp.Height = 100;
cp.Width = 100;

            // Create as a child of the specified parent
cp.Parent = parent.Handle;
cp.Style = WS_VISIBLE | SBS_VERT | WS_CHILD;

            IntPtr modHandle = NativeScrollBar.GetModuleHandle(null);

            IntPtr handleCreated = IntPtr.Zero;
int lastWin32Error = 0;
try
{
// Create the actual scrollbar window
handleCreated = NativeScrollBar.CreateWindowEx(cp.ExStyle, cp.ClassName,
cp.Caption, cp.Style, cp.X, cp.Y, cp.Width, cp.Height, new HandleRef(cp, cp.Parent), new HandleRef(null, IntPtr.Zero),
new HandleRef(null, modHandle), cp.Param);
lastWin32Error = Marshal.GetLastWin32Error();
}
catch (NullReferenceException e)
{
throw new OutOfMemoryException("Could not create Native Window");
}
if (handleCreated == IntPtr.Zero)
{
throw new Win32Exception(lastWin32Error, "System error creating Native Window");
}

            // Now assign the NativeWindow handle to the native scroll bar
this.AssignHandle(handleCreated);

        }

        // Constant values were found in the "windows.h" header file.
private const int WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
SBS_HORZ = 0x0000,
SBS_VERT = 0x0001;
[DllImport("USER32.DLL", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CreateWindowEx(int dwExStyle, string lpszClassName,
string lpszWindowName, int style, int x, int y, int width, int height,
HandleRef hWndParent, HandleRef hMenu, HandleRef hInst, [MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("KERNEL32.DLL", CharSet = CharSet.Auto)]
private static extern IntPtr GetModuleHandle(string modName);

    }

}