Introduction
First of all, I must stress upon that I am no author and this is my first article ever. I am not even sure whether I would continue to write. I am solely writing this so that, it would prevent someone else going through the hassle of what I went through to discover this solution. Most probably, I would not have time to improve or do bug fixes, if any.
Secondly, this is
not my code/thought. I just merely updated it so, that it would provide more flexibility.
The original owner of this code is CodeProject user Karin Huber and all I did was improving her code from the article "Scroll Synchronization".
Background

As you can see from the above screenshot (I was lazy to make a comprehensive UI), consider a scenario where you have to synchronize two scroll bars (i.e., one would be automatically scrolled, when the other is scrolled). In conventional windows programming we would capture the offset in the code behind and we write the logic. But as we move into WPF, we are introduced to MVVM architecture (I won't be dwelling on this very much) where data binding is everything and code behinds are evil
But sadly, scroll viewers cannot be bound as such, owing to the fact that the developer who developed this control did not implement the required properties as 'DependencyProperty'.
So in the above mentioned article, this scenario is addressed and solved very elegantly. The only bottleneck was that, he synchronized both scroll bars. I wanted them to be bound separately/independent, which is what I have achieved in this attempt.
Using the code
This article will not describe the solution in detail. So please, read the above referenced article.
I would not go into detail about DependencyProperty objects in C#, but
for the record, this entire solution is based on Dependency Properties.
So, if you do not know about it, please read about them. There are many
valuable CP articles on that topic.
Also, I won't go into much technical details as Karin's article covers pretty much all the details. I'd explain how to use my code.
The solution is implemented in the ScrollSynchronizer
and to there are three DependencyProperty
implemented like this:
public static readonly DependencyProperty HorizontalScrollGroupProperty =
DependencyProperty.RegisterAttached(HorizontalScrollGroupPropertyName, typeof(string),
typeof(ScrollSynchronizer), new PropertyMetadata(string.Empty, OnHorizontalScrollGroupChanged));
public static readonly DependencyProperty VerticalScrollGroupProperty =
DependencyProperty.RegisterAttached(VerticalScrollGroupPropertyName, typeof(string),
typeof(ScrollSynchronizer), new PropertyMetadata(string.Empty, OnVerticalScrollGroupChanged));
public static readonly DependencyProperty ScrollSyncTypeProperty =
DependencyProperty.RegisterAttached(ScrollSyncTypePropertyName, typeof(ScrollSyncType),
typeof(ScrollSynchronizer), new PropertyMetadata(ScrollSyncType.None, OnScrollSyncTypeChanged));
To use these properties, refer as below in your XAML:
xmlns:Core="clr-namespace:ScrollViewerSynchronization.Core"
After that, you can use them like:
<ScrollViewer Grid.Row="0" Grid.Column="0" HorizontalScrollBarVisibility="Visible"
Core:ScrollSynchronizer.VerticalScrollGroup="V1" Core:ScrollSynchronizer.HorizontalScrollGroup="H1">
As you may have noticed, these properties inject themselves into ScrollViewer
type in XAML. Assuming, now you know how to use the code,
I'll explain how to use these properties.
Important thing is, none of the properties are dependent on each other. I.e. you can use these individually or as a combination as preferred.
VerticalScrollGroup
: The data type of the property is
string
. All scrollviewers having the same value for this property is
vertically scrolled together. Default value: string.Empty
HorizontalScrollGroup
: The data type of the property is
string
. All scrollviewers having the same value for this property is
horizontally scrolled together. Default value: string.Empty
ScrollSyncType
: The data type of the property is ScrollSyncType
enum which is defined within the class. There are
four possible values:
None
: Default value of this property. Scrolling will be disabled.
Horizontal
: Scrolling synced only horizontal.
Vertical
: Scrolling synced only vertical.
Both
: Scrolling synced both vertical and horizontal.
If you set VerticalScrollGroup
without setting ScrollSyncType
, it will automatically be assigned to
ScrollSyncType.Vertical
. If the ScrollSyncType
was set to
ScrollSyncType.Horizontal
, it would be updated to ScrollSyncType.Both
. This logic applies to
HorizontalScrollGroup
as well.
If you set
ScrollSyncType
without setting VerticalScrollGroup
or
HorizontalScrollGroup
, the synchronizing will be done accordingly assuming that the VerticalScrollGroup = string.Empty
and HorizontalScrollGroup = string.Empty
Points of Interest
Once again special thanks to Kavin Huber for that wonderful article which pointed me in this way. I discovered a new way of thinking to push the boundaries/limitations of WPF XAML.
I hope someone would be benefited out of this article.