ScrollViewer customization

|

Another StackOverflow question; this time about making a ListBox cycle its contents when scrolling. The question:

WPF ListBox: Can you make it cycle? i.e. not hit hard stops at top and bottom

Seems like a pretty simple request: make a circular list, i.e. when you roll off the end of the list start from the beginning again (or end depending on which direction you scrolled in). After a quick examination of the control template for a ListBox I figured that a good solution might be to try and work with the ScrollViewer control, and see if I could get that to cycle... then I could simply replace the ScrollViewer instance in the control template for the ListBox, job done!

So that's what I did:

public class CyclicScrollViewer : ScrollViewer
{
    public CyclicScrollViewer()
    {
      this.CommandBindings.Add(new CommandBinding(ScrollBar.LineUpCommand, LineCommandExecuted));
      this.CommandBindings.Add(new CommandBinding(ScrollBar.LineDownCommand, LineCommandExecuted));
    }

    private void LineCommandExecuted(object sender, ExecutedRoutedEventArgs e)
    {
      if (e.Command == ScrollBar.LineUpCommand)
      {
          if (this.VerticalOffset == 0)
              this.ScrollToEnd();
          else
              this.LineUp();
      }

      if (e.Command == ScrollBar.LineDownCommand)
      {
          if (this.VerticalOffset == this.ScrollableHeight)
              this.ScrollToTop();
          else
              this.LineDown();
      }
   }
}

This code simply installs event handlers for the LineUpCommand and LineDownCommand commands dispatched by the vertical ScrollBar in the control template for the ScrollViewer. Which, by the way, is a seriously fabulous way for this control to behave. In the event handler I examine incoming command type, then dispatch to the LineUp or LineDown methods as appropriate. However, before that I do a check to see if the control is already fully scrolled to either the top or the bottom of the viewer, and then, depending on the command, call either ScrollToEnd or ScrollToTop to loop the ScrollViewer - all the methods used, and more, already exist on the ScrollViewer, making the coding a very simple affair.

I've uploaded a sample application that uses the new ScrollViewer here:

PaulJ.CyclicListBox.zip

This sample is clearly incomplete; it only handles vertical scrolling. However, you can see how it could be extended to handle horizontal scrolling too. In fact, I intend to hack on this a little more in the coming weeks and try and create a complete working control... unless another question catches my eye in the meantime ;)

I may also look into providing a Silverlight version, but that'll largely depend on the comments get back from this post, so let me know if you think that'll be a good idea.

As always, comments and suggestions very welcome.

No comments: