Making FlowLayoutPanel Scroll Using Arrow Keys, Page Up, Page Down

February 06, 2007

How do you make the FlowLayoutPanel scroll using arrow keys, page up, page down?

I'll start with the answers and work backwards: Subscribe to the PreviewKeyDown event and don't forget to call control.PerformLayout().

Now the problem: If you haven't checked out the NYTimes Reader application, you're totally missing out.  It's this fantastic .NET 3 / WPF app that gives the absolute BEST newspaper reading experience ever. **

Anyway, I also subscribe to the Wall Street Journal and they don't have a nice reader application.  I've emailed them to complain and the answer was a predictable “no soup for you”.  So I decided to write my own.

Since you don't know how many articles you're going to have in the paper each day and I needed to display a formatted list of dynamic controls, I needed to use the FlowLayoutPanel.  Since you can add more controls to the panel than could be displayed in the control's visible area, you need scrolling capability.  FlowLayoutPanel has the AutoScroll feature but (oddly) doesn't appear to answer anything typical like the arrow keys or page up or page down for scrolling.  (It answers the mouse scroll event just fine.  Nutty.)

In order to make the scrolling actually work, I needed to hook up to a keyboard event.  I looked at the FlowLayoutPanel's events expecting to see KeyUp, KeyDown, and/or KeyPress.  Nope.  A little bit of hunting around and the answer is the PreviewKeyDown event.

Here's part of my implementation:

private void m_flowArticles_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
try
{
if (e.KeyCode == Keys.Up)
{
ScrollUp(m_flowArticles, false);
}
else if (e.KeyCode == Keys.Down)
{
ScrollDown(m_flowArticles, false);
}
else if (e.KeyCode == Keys.PageUp)
{
ScrollUp(m_flowArticles, true);
}
else if (e.KeyCode == Keys.PageDown)
{
ScrollDown(m_flowArticles, true);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

private void ScrollUp(ScrollableControl control, bool isLargeChange)
{
if (control == null)
{
return;
}

int changeAmount;

if (isLargeChange == false)
{
changeAmount = control.VerticalScroll.SmallChange * 3; 
}
else

int currentPosition = control.VerticalScroll.Value;

if ((currentPosition - changeAmount) > control.VerticalScroll.Minimum)
{
control.VerticalScroll.Value -= changeAmount;
}
else

control.PerformLayout();
}

The scrolling with the arrow keys was simple.  Making PageDown and PageUp work properly took more effort.  Pressing PageUp or PageDown only worked every other time.  I'd press PageDown or PageUp and the scroll bar would move but the FlowLayoutPanel wouldn't actually scroll to a new page.  The answer to that problem was to call “PerformLayout()“ on the FlowLayoutControl.

Now it works fine.

-Ben

** -- Reading the physical paper sucks (dirty, lots of trash, cumbersome, and noisy).  Reading the regular NYTimes.com website is less sucky but it's tough to get a feel for what's IN the paper.  The NYTimes Reader gives you the best of both worlds: it's clean, no trash, easy to move around, no crumpling paper noises, easy to get a quick feel for what you want to read.  It's awesome.  Really really awesome.  (I still won't read Tom Friedman's column...but that's a totally separate issue.)

Categories: news tech