如何链接滚动条和滚动查看器

时间:2010-12-02 00:16:18

标签: wpf scrollbar scrollviewer

我目前有两个ScrollViewer包含同一集合的备用视图。我通过处理ScrollChanged事件并使用ScrollToVerticalOffset将两个滚动查看器的滚动绑定在一起。

出于演示原因,我已将ScrollViewer滚动条设置为隐藏,并希望从单独的ScrollBar控制它们。

这似乎并不简单。我记得几个月前看过一篇关于它的博客,但我再也找不到了。

任何人都可以向我指出一些有用的资源,或者向我推动如何实现这一目标的正确方向。

提前致谢。

2 个答案:

答案 0 :(得分:11)

很好,正是我需要的。我扩展了一点,以便可以使用依赖属性从xaml设置scrollviewer。在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; 
        } 
    }
}

答案 1 :(得分:7)

好的,解决了这个问题。其实很简单。

此后发现Wpf binding to a function,这应该有助于其他任何感兴趣的人。它的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;
        }
    }
}