Scrolling Multiple Content Areas with a single ScrollBar in WPF

March 12th, 2009 by ryan Leave a reply »

I struggled to solve a UI dilemma while at my current client.  For various reasons, we came across a situation in which we needed to scroll two areas of the view based on a single Scrollbar.  You can see what we were attempting and finally achieved here.

The end result is smooth, yet not quite intuitive so I thought I would share the results and steps taken.  The idea is to use a surrogate ScrollViewer as the source for the offset of a TranslateTransform being applied to content within a seperate ScrollViewer.

Unfortunately, the offset values exposed by the ScrollViewer are both readonly and opposite in force to which we would need to apply to the surrogate.  That is, if we scroll 20 units to the right on our ScrollViewer, we would need to offset the surrogate ScrollViewer by that amount in the opposite direction.  To resolve this problem, we use an IValueConverter to multiple the offset by –1.

Here we can see the Xaml used to layout and hookup this scenario:

<StackPanel>
    <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
        <Grid>
            <Grid.RenderTransform>
                <TranslateTransform X="{Binding ElementName=mainScroller, Path=HorizontalOffset, Converter={StaticResource multiplyConv}, ConverterParameter=-1}" />
            </Grid.RenderTransform>
            <!-- Content Scrolled by another goes here -->
        </Grid>
    </ScrollViewer>
    <ScrollViewer x:Name="mainScroller" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <!-- Content Scrolled on its own accord goes here-->
    </ScrollViewer>
</StackPanel>

You can see that we have two ScrollViewers and the one which will be controlled (versus the controller) has a container element with a TranslateTransform applied to its RenderTransform property.  This is what we will be using to move the controlled content in the opposite direction of the ScrollBar.

If you find that your content for each are not the same size, you can always use a MultiBinding to accomodate the relative scrolling distance as applied to the offset.

You can find the source to the sample Xbap here.

Advertisement

Leave a Reply