Хорошо, это действительно старый вопрос, но я подумал, что поделюсь для потомков, так как сам решил этот вопрос. Лучшее решение, которое я нашел, - это создать пользовательский элемент управления, производный от класса ScrollView и реализующий нужные вам свойства, которые, конечно, связаны с несвязываемыми свойствами базового класса.
Вы можете использовать функцию OnPropertyChanged для мониторинга этих свойств и синхронизации значений.
Вот полный код моего пользовательского элемента управления под названием DynamicScrollViewer. Обратите внимание, что у меня есть четыре привязываемых свойства зависимости, которые называются DynamicHorizontOffset, DynamicVerticalOffset, DynamicViewportWidth и DynamicViewportHeight.
Два свойства смещения позволяют контролировать смещение как для чтения, так и для записи, в то время как свойства области просмотра по существу доступны только для чтения.
Мне пришлось использовать этот класс при создании сложного элемента управления редактора анимации, в котором различные компоненты (метки слева, узлы посередине, временная шкала вверху) должны были прокручиваться синхронно, но только в ограниченных аспектах, и были связаны на общие внешние полосы прокрутки. Подумайте о блокировке секции строк в электронной таблице, и вы поймете идею.
using System.Windows;
using System.Windows.Controls;
namespace CustomControls
{
public partial class DynamicScrollViewer : ScrollViewer
{
public DynamicScrollViewer()
{
InitializeComponent();
}
public double DynamicHorizontalOffset
{
get { return (double)GetValue(DynamicHorizontalOffsetProperty); }
set { SetValue(DynamicHorizontalOffsetProperty, value); }
}
public static readonly DependencyProperty DynamicHorizontalOffsetProperty =
DependencyProperty.Register("DynamicHorizontalOffset", typeof(double), typeof(DynamicScrollViewer));
public double DynamicVerticalOffset
{
get { return (double)GetValue(DynamicVerticalOffsetProperty); }
set { SetValue(DynamicVerticalOffsetProperty, value); }
}
public static readonly DependencyProperty DynamicVerticalOffsetProperty =
DependencyProperty.Register("DynamicVerticalOffset", typeof(double), typeof(DynamicScrollViewer));
public double DynamicViewportWidth
{
get { return (double)GetValue(DynamicViewportWidthProperty); }
set { SetValue(DynamicViewportWidthProperty, value); }
}
public static readonly DependencyProperty DynamicViewportWidthProperty =
DependencyProperty.Register("DynamicViewportWidth", typeof(double), typeof(DynamicScrollViewer));
public double DynamicViewportHeight
{
get { return (double)GetValue(DynamicViewportHeightProperty); }
set { SetValue(DynamicViewportHeightProperty, value); }
}
public static readonly DependencyProperty DynamicViewportHeightProperty =
DependencyProperty.Register("DynamicViewportHeight", typeof(double), typeof(DynamicScrollViewer));
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == DynamicVerticalOffsetProperty)
{
if (ScrollInfo != null)
ScrollInfo.SetVerticalOffset(DynamicVerticalOffset);
}
else if (e.Property == DynamicHorizontalOffsetProperty)
{
if (ScrollInfo != null)
ScrollInfo.SetHorizontalOffset(DynamicHorizontalOffset);
}
else if (e.Property == HorizontalOffsetProperty)
{
DynamicHorizontalOffset = (double)e.NewValue;
}
else if (e.Property == VerticalOffsetProperty)
{
DynamicVerticalOffset = (double)e.NewValue;
}
else if (e.Property == ViewportWidthProperty)
{
DynamicViewportWidth = (double)e.NewValue;
}
else if (e.Property == ViewportHeightProperty)
{
DynamicViewportHeight = (double)e.NewValue;
}
}
}
}