Как связать полосу прокрутки и scrollviewer - PullRequest
6 голосов
/ 02 декабря 2010

В настоящее время у меня есть два ScrollViewer, содержащих альтернативные представления одной и той же коллекции. Я связал прокрутку двух скроллверов вместе, обрабатывая событие ScrollChanged и используя ScrollToVerticalOffset.

В целях презентации я установил обе полосы прокрутки ScrollViewer на скрытые и хочу управлять ими с отдельной панели прокрутки.

Кажется, это не так просто. Я помню, как видел блог об этом несколько месяцев назад, но не могу найти его снова.

Может ли кто-нибудь указать мне на некоторые полезные ресурсы или дать мне толчок в правильном направлении к тому, как этого можно достичь.

Заранее спасибо.

Ответы [ 2 ]

12 голосов
/ 18 февраля 2011

Отлично, как раз то, что мне было нужно.Я немного расширил, чтобы scrollviewer можно было установить и из xaml, используя свойство зависимости.В xaml:

<local:BindableScrollBar BoundScrollViewer ="{Binding ElementName=ScrollViewer}"  Orientation="Vertical" />

Код:

    /// <summary>
/// An extended scrollbar that can be bound to an external scrollviewer.
/// </summary>
public class BindableScrollBar : ScrollBar
{
    public ScrollViewer BoundScrollViewer
    {
        get { return (ScrollViewer)GetValue(BoundScrollViewerProperty); }
        set { SetValue(BoundScrollViewerProperty, value); }
    }

    // Using a DependencyProperty as the backing store for BoundScrollViewer.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty BoundScrollViewerProperty =
        DependencyProperty.Register("BoundScrollViewer", typeof(ScrollViewer), typeof(BindableScrollBar), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnBoundScrollViewerPropertyChanged)));

    private static void OnBoundScrollViewerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        BindableScrollBar sender = d as BindableScrollBar;
        if (sender != null && e.NewValue != null)
        {
            sender.UpdateBindings();
        }
    }



    /// <summary>
    /// Initializes a new instance of the <see cref="BindableScrollBar"/> class.
    /// </summary>
    /// <param name="scrollViewer">The scroll viewer.</param>
    /// <param name="o">The o.</param>
    public BindableScrollBar(ScrollViewer scrollViewer, Orientation o)
        : base()
    { 
        this.Orientation = o;
        BoundScrollViewer = scrollViewer; 
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="BindableScrollBar"/> class.
    /// </summary>
    public BindableScrollBar() : base() { }

    private void UpdateBindings()
    {
        AddHandler(ScrollBar.ScrollEvent, new ScrollEventHandler(OnScroll));
        BoundScrollViewer.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(BoundScrollChanged));
        Minimum = 0;
        if (Orientation == Orientation.Horizontal)
        {
            SetBinding(ScrollBar.MaximumProperty, (new Binding("ScrollableWidth") { Source = BoundScrollViewer, Mode = BindingMode.OneWay }));
            SetBinding(ScrollBar.ViewportSizeProperty, (new Binding("ViewportWidth") { Source = BoundScrollViewer, Mode = BindingMode.OneWay }));
        }
        else 
        {
            this.SetBinding(ScrollBar.MaximumProperty, (new Binding("ScrollableHeight") { Source = BoundScrollViewer, Mode = BindingMode.OneWay }));
            this.SetBinding(ScrollBar.ViewportSizeProperty, (new Binding("ViewportHeight") { Source = BoundScrollViewer, Mode = BindingMode.OneWay })); 
        } 
        LargeChange = 242; 
        SmallChange = 16;
    }

    private void BoundScrollChanged(object sender, ScrollChangedEventArgs e) 
    { 
        switch (this.Orientation) 
        { 
            case Orientation.Horizontal:
                this.Value = e.HorizontalOffset;
            break;
            case Orientation.Vertical:
                this.Value = e.VerticalOffset; 
                break; 
            default:
                break; 
        }
    }

    private void OnScroll(object sender, ScrollEventArgs e) 
    {
        switch (this.Orientation) 
        {
            case Orientation.Horizontal:
                this.BoundScrollViewer.ScrollToHorizontalOffset(e.NewValue);
                break;
            case Orientation.Vertical:
                this.BoundScrollViewer.ScrollToVerticalOffset(e.NewValue);
                break; 
            default: 
                break; 
        } 
    }
}
7 голосов
/ 02 декабря 2010

Хорошо, решил это.На самом деле было довольно просто.

С тех пор нашли Wpf-привязку к функции , которая должна помочь всем, кто заинтересован.Его VB, но должно быть достаточно ясным.

Приветствия

В дополнение к вышесказанному: я создал подкласс ScrollBar и передал ScrollViewer, который я хотел привязать.Кажется, работает нормально.

public class ScrollViewerBoundScrollBar : ScrollBar
{
    private ScrollViewer _scrollViewer;
    public ScrollViewer BoundScrollViewer { get { return _scrollViewer; } set { _scrollViewer = value; UpdateBindings(); } }

    public ScrollViewerBoundScrollBar( ScrollViewer scrollViewer, Orientation o ) : base()
    {   
        this.Orientation = o;
        BoundScrollViewer = _scrollViewer;
    }

    public ScrollViewerBoundScrollBar() : base()
    {
    }

    private void UpdateBindings()
    {
        this.AddHandler(ScrollBar.ScrollEvent, new ScrollEventHandler(OnScroll));
        _scrollViewer.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(BoundScrollChanged));
        this.Minimum = 0;
        if (Orientation == Orientation.Horizontal)
        {
            this.SetBinding(ScrollBar.MaximumProperty, (new Binding("ScrollableWidth") { Source = _scrollViewer, Mode = BindingMode.OneWay }));
            this.SetBinding(ScrollBar.ViewportSizeProperty, (new Binding("ViewportWidth") { Source = _scrollViewer, Mode = BindingMode.OneWay }));
        }
        else
        {
            this.SetBinding(ScrollBar.MaximumProperty, (new Binding("ScrollableHeight") { Source = _scrollViewer, Mode = BindingMode.OneWay }));
            this.SetBinding(ScrollBar.ViewportSizeProperty, (new Binding("ViewportHeight") { Source = _scrollViewer, Mode = BindingMode.OneWay }));
        }
        this.LargeChange = 242;
        this.SmallChange = 16;
    }

    public void BoundScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        switch (this.Orientation)
        {
            case Orientation.Horizontal:
                this.Value = e.HorizontalOffset;
                break;
            case Orientation.Vertical:
                this.Value = e.VerticalOffset;
                break;
            default:
                break;
        }
    }

    public void OnScroll(object sender, ScrollEventArgs e)
    {
        switch(this.Orientation)
        {
            case Orientation.Horizontal:
                this.BoundScrollViewer.ScrollToHorizontalOffset(e.NewValue);
                break;
            case Orientation.Vertical:
                this.BoundScrollViewer.ScrollToVerticalOffset(e.NewValue);
                break;
            default:
                break;
        }
    }
}
...