Working With a ScrollViewer

Navigating a ScrollViewer (Visual Studio 2012)

A scrollviewer is a UI Element in C# for Windows 8 programming. It is useful for when the objects you desire to show are larger than the screen. Putting objects in a scrollviewer allows you to put these objects in a bounded box. You’ll be able to scroll around using offsets and zoom.

To begin, pull a ScrollViewer from the Toolbox and drop it onto the design view of your xaml code. Size, position, and name it to your choosing. You will also want to set the Horizontal and Vertical Scroll Bar Visibility settings to Auto. Or you can write the xaml code directly into your xaml file. Either way, you should end up with code similar to

<ScrollViewer x:Name="myScroll" HorizontalAlignment="Left" Height="534"
Margin="113,145,0,0" VerticalAlignment="Top" Width="491"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"/>

in your xaml file. Naming is important in order to access the many features programmatically. Next, let’s put some objects in the scrollviewer. To be able to put multiple objects in a scrollviewer, you will need some kind of layout. Let’s place a Grid into the scrollviewer. First, obtain a grid from a toolbox, drag it onto the page, and name it (for this example, myScrollGrid). Then, hover the grid over your scrollviewer. While hovering, you should see a popup that says, “hold alt to place inside myScrollGrid”. Do so. Then, size your grid to the same size as your scrollviewer. This is not necessary, but recommended. Your code should now look similar to:

<ScrollViewer x:Name="myScroll" HorizontalAlignment="Left" Height="534" 
Margin="113,145,0,0" VerticalAlignment="Top" Width="491">
            <Grid x:Name="myScrollGrid" Height="534" Width="491"/>
</ScrollViewer>

Now, let’s put some objects in our scroll viewer. Let’s keep it simple, and put 4 rectangles from the toolbox into the grid, remembering to hold alt to place inside the grid. Make them unique so that, when you are scrolling you can tell them apart. In this example, I’ve named them “rect” followed by a number, and then changed their colors under the Fill section of its properties. Place the rectangles a good amount of distance from each other. The code should resemble:

   <ScrollViewer x:Name="myScroll" HorizontalAlignment="Left" Height="534" 
                 Margin="113,145,0,0" VerticalAlignment="Top" Width="491"
                 HorizontalScrollBarVisibility="Auto" 
                 VerticalScrollBarVisibility="Auto">
            <Grid x:Name="myScrollGrid" Height="534" Width="491">
                <Rectangle x:Name="rect2" Fill="Blue" HorizontalAlignment="Left" 
                           Height="100" Margin="393,1,-2,0" Stroke="Black" 
                           VerticalAlignment="Top" Width="100"/>
                <Rectangle x:Name="rect1" Fill="#FFF4F4F5" 
                           HorizontalAlignment="Left" Height="100"
                           Margin="2,2,0,0" Stroke="Black" 
                           VerticalAlignment="Top" Width="100"/>
                <Rectangle x:Name="rect4" Fill="Red" 
                           HorizontalAlignment="Left" Height="100" 
                           Margin="391,434,0,0" Stroke="Black" 
                           VerticalAlignment="Top" Width="100"/>
                <Rectangle x:Name="rect3" Fill="#FF4AB040"
                           HorizontalAlignment="Left" Height="100" 
                           Margin="0,433,0,0" Stroke="Black" 
                           VerticalAlignment="Top" Width="100"/>
            </Grid>

And here is an image of what all of this looks like so far, when you run it:

Image Hosted by ImageShack.us

It’s not particularly exciting, because the grid is the same size as the scrollviewer. An alternative would be to work on a grid larger than the scrollviewer and, when that is finished, drag the completed grid into the scrollviewer. But for now, let’s work with this. Open up your .cs file that corresponds to this xaml. In the function OnNavigatedTo, let’s make some changes to the scrollviewer. To see some scrolling, we could benefit from zooming in. To do so, use this code:

myScroll.ZoomToFactor(2);

The ZoomFactor of a scrollviewer starts at 1, so this doubles the size of everything in the scrollviewer. So now, when you run the program, you’ll only be able to see some objects in the scrollviewer, and you can use the scrollbars to see

Image Hosted by ImageShack.us

Feel free to set the maxZoomFactor and minZoomFactor either in the code C#:

myScroll.MaxZoomFactor = 5;

or in the xaml:

 <ScrollViewer x:Name="myScroll" HorizontalAlignment="Left" Height="534" 
Margin="113,145,0,0" VerticalAlignment="Top" Width="491" 
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" 
MaxZoomFactor="5">

Let’s create a way of zooming in and out. I would recommend using the app bar for this, but, to keep the example simple, we can use buttons instead. Drag a couple buttons from the toolbox onto the side of your scroll viewer. One of them for zooming in, the other for zooming out. Also, make an on click action called Button_Click. Your xaml code should look similar to:

<Button x:Name="ZoomIn" Content="Zoom In"  HorizontalAlignment="Left" 
VerticalAlignment="Top" Margin="878,166,0,0" Click="Button_Click" Width="200"/>
<Button x:Name="ZoomOut" Content="Zoom Out"  HorizontalAlignment="Left" 
VerticalAlignment="Top" Margin="878,248,0,0" Click="Button_Click" Width="200"/>

Now, back in your C# file, we can determine how much to zoom in or out using these recently created buttons and ZoomToFactor. You can handle this however you see fit, but here is some example code for your Button_Click function:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
 /* Zoom factor buttons */
 if (sender == ZoomOut)
 {
 myScroll.ZoomToFactor(myScroll.ZoomFactor - 1);
 }
 else if (sender == ZoomIn)
 {
 if (myScroll.ZoomFactor &lt; 1)
 myScroll.ZoomToFactor(1);
 else
 myScroll.ZoomToFactor(myScroll.ZoomFactor + 1);
 }

if (myScroll.ZoomFactor == myScroll.MaxZoomFactor)
 ZoomIn.IsEnabled = false;
 else
 ZoomIn.IsEnabled = true;

if (myScroll.ZoomFactor == myScroll.MinZoomFactor)
 ZoomOut.IsEnabled = false;
 else
 ZoomOut.IsEnabled = true;
 }
 

Now run your app again.

Image Hosted by ImageShack.us

You can now zoom in and zoom out as you please, and the scrollbars will adjust accordingly. Now let’s attempt some form of navigation. Each rectangle is identified by its own name, so we can use its properties to scroll automatically to them. Before we go further, I suggest putting the rectangles in an array so that they can be accessed numerically. I would recommend having these two variables outside of your functions:

Windows.UI.Xaml.Shapes.Rectangle[] rects = new Windows.UI.Xaml.Shapes.Rectangle[4];
int currentRect = -1;

And initializing the array in the OnNavigatedTo function:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
rects[0] = rect1;
rects[1] = rect2;
rects[2] = rect3;
rects[3] = rect4;
myScroll.ZoomToFactor(2);
}

Now that the foundational work is done, let’s make two buttons, in the xaml file, for navigation: Next and Previous. Use the same “Button_Click” function for them.

  <Button x:Name="Next" Content="Next"  HorizontalAlignment="Left" 
VerticalAlignment="Top" Margin="404,40,0,0" Click="Button_Click" Width="200"/>
  <Button x:Name="Previous" Content="Previous"  HorizontalAlignment="Left" 
VerticalAlignment="Top" Margin="113,40,0,0" Click="Button_Click" Width="200"/>

And let’s wire up some code in the C# file:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
 /* Zoom factor buttons */
 if (sender == ZoomOut)
 {
 myScroll.ZoomToFactor(myScroll.ZoomFactor - 1);
 }
 else if (sender == ZoomIn)
 {
 if (myScroll.ZoomFactor &lt; 1)
 myScroll.ZoomToFactor(1);
 else
 myScroll.ZoomToFactor(myScroll.ZoomFactor + 1);
 }
 /* Navigation buttons */
 else if (sender == Next)
 {
 if (currentRect == -1 || currentRect == 3)
 currentRect = 0;
 else
 currentRect++;

myScroll.ScrollToHorizontalOffset(rects[currentRect].Margin.Left);
 myScroll.ScrollToVerticalOffset(rects[currentRect].Margin.Top);
 }
 else if (sender == Previous)
 {
 if (currentRect == -1 || currentRect == 0)
 currentRect = 3;
 else
 currentRect++;

myScroll.ScrollToHorizontalOffset(rects[currentRect].Margin.Left);
 myScroll.ScrollToVerticalOffset(rects[currentRect].Margin.Top);
 }

/*Zoom factor follow up */
 if (myScroll.ZoomFactor == myScroll.MaxZoomFactor)
 ZoomIn.IsEnabled = false;
 else
 ZoomIn.IsEnabled = true;

if (myScroll.ZoomFactor == myScroll.MinZoomFactor)
 ZoomOut.IsEnabled = false;
 else
 ZoomOut.IsEnabled = true;
 }
 

What is happening the the variable currentRect is it treats the rectangle array as a circular array. So the 0th element can go to the 3rd element and the reverse it true. The navigation occurs with the calls ScrollToHorizontalOffset and ScrollToVerticalOffset, which takes in an integer value. The best way I’ve found to identify an objects position is to examine its margin. Particularly, the Left and Top values. You may have to experiment with these numbers (for example using the height/width of the image and the scrollviewer) in order to get the image where you want it.

About David Lafontant

David is currently pursuing his B.S Degree in Computer Science from the Florida State University. Captivated by programming, he is interested in broadening his scope of programming languages. He enjoys the problem solving aspect of coding and has an aptitude for mathematics. David’s primary focus is in the development and maintenance of software.