July 06, 2004

.NET Annoyances #1

The Annoyance

I have a control that derives from System.Windows.Forms.ScrollableControl. Great. I write my control, which is a kind of square grid that extends beyond the Window’s bounds. Great. I scroll my control and see that my control is not repainted the revealed areas. Curious. I think to myself, oh, simple, I’ll just override the scroll event and invalidate my Window. I mean, a ScrollableControl has to have a bloody Scroll event, right?

Wrong!

There is no scroll event for a Scrollable Control. I thought I would inaugurate my new column with a gem like this. Providing a Scrollable Control that doesn’t have a Scroll event is like providing a custom control that can’t be customized. Or, to put it in everyday terms, it’s like going into a candy store with your son and leaving without buying him so much as a lollipop.

The Solution

I wanted my lollipop. As usual Code Project came to the rescue. However, once I saw the solution I kicked myself since I should have thought of it myself. The key to the solution is the override of the WndProc and simply handling the WM_HSCROLL, WM_VSCROLL, and SBM_SETSCROLLINFO messages. Here is the class that I found on Code Project, written by Martin Randall:

    public class ScrollableControlEx : System.Windows.Forms.ScrollableControl

    {

        private sealed class NativeMethods

        {

            public const int SBM_SETSCROLLINFO = 0×00E9;

            public const int WM_HSCROLL = 0×115;

            public const int WM_VSCROLL = 0×114;

        }

 

        [Browsable(false)]

        public Point ScrollPosition

        {

            get { return new Point(-AutoScrollPosition.X, -AutoScrollPosition.Y); }

            set { AutoScrollPosition = value; }

        }

 

        public event EventHandler Scroll;

 

        protected virtual void OnScroll()

        {

            if (Scroll != null)

            {

                Scroll(this, EventArgs.Empty);

            }

        }

 

        protected override void WndProc(ref Message m)

        {

            base.WndProc (ref m);

 

            if (m.Msg == NativeMethods.WM_HSCROLL ||

                m.Msg == NativeMethods.WM_VSCROLL ||

                m.Msg == NativeMethods.SBM_SETSCROLLINFO)

            {

                OnScroll();

            }

        }

    }

 

Discussion

 

If your drawing is particularly expensive, you probably want to invalidate only the portion of the Window that gets exposed as a result of the scroll. The above code doesn’t do that since the Scroll event doesn’t contain the needed information. This information is contained in the low and high words of the WParam property of the Message class shown above. In addition, you’ll need the page size found in the SCROLLINFO structure (see the Win32 SDK).

 

A more complete implementation of this extended class would provide this information to the Scroll event so you should be able to invalidate the proper portions of the display.

 

In my case, invaliding the Window was fast enough so I didn’t bother. If this changes, I’ll write up the solution and post it.

 

 

Posted by Nick Codignotto at July 6, 2004 11:04 PM | TrackBack
Posted to .NET Annoyances | Programming
Comments
Post a comment









Remember personal info?






Valid XHTML 1.0!   Valid CSS!