Привязка к ScrollViewer ViewportWidth и ViewportHeight - PullRequest
2 голосов
/ 16 июля 2010

Я использую архитектуру Model-View-ViewModel в создаваемом мною приложении WPF, и я хотел бы, чтобы конкретная модель ViewModel действительно реагировала на размер представления (не обычный сценарий использования подхода MVVM, Я знаю).

По сути, у меня есть объект ScrollViewer, и я хочу, чтобы модель просмотра наблюдала ширину и высоту средства просмотра прокрутки, а затем смогла бы действовать соответствующим образом в зависимости от того, что это за ширина и высота.

Я бы хотел сделать что-то вроде этого:

<ScrollViewer ViewportWidth="{Binding Path=MyViewportWidth, Mode=OneWayToSource}" ViewportHeight="{Binding Path=MyViewportHeight, Mode=OneWayToSource}" />

Но, конечно, это невозможно сделать, потому что «ViewportWidth» и «ViewportHeight» не могут быть «привязаны к» (иначе говоря, действуют как цели привязки), потому что они являются свойствами зависимости только для чтения (даже если я не пишу им все в этой привязке, так как это OneWayToSource).

Кто-нибудь знает хороший метод, чтобы иметь возможность делать что-то подобное?

Ответы [ 2 ]

1 голос
/ 09 декабря 2015

Хорошо, это действительно старый вопрос, но я подумал, что поделюсь для потомков, так как сам решил этот вопрос. Лучшее решение, которое я нашел, - это создать пользовательский элемент управления, производный от класса 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;
            }
        }
    }
}
1 голос
/ 16 июля 2010

Вы можете попробовать запустить что-нибудь OnLoaded или OnResizeChanged, которые обновляют модель представления

private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
   ScrollViewer sv = sender as ScrollViewer;
   ViewModel vm = sv.DataContext as ViewModel;

   vm.ScrollViewerHeight = sv.ViewportHeight;
   vm.ScrollViewerWidth = sv.ViewportWidth;
}
...