Search code examples
wpfscrollbarscrollviewer

How to link scrollbar and scrollviewer


I currently have two ScrollViewer's containing alternate views of the same collection. I have bound the scrolling of the two scrollviewers together by handling the ScrollChanged event and using ScrollToVerticalOffset.

For presentation reasons I have set both ScrollViewer scrollbars to hidden and want to control them both from a seperate ScrollBar.

This seems to not be straightforward. I recall seeing a blog about it a few months ago but I can't find it again.

Can anyone point me in the direction of some useful resources or give me a shove in the right direction to how it might be achieved.

Thanks in advance.


Solution

  • Ok, solved this. Was actually quite straightforward.

    Have since found Wpf binding to a function, which should help anyone else interested. Its VB but should be clear enough.

    Cheers

    Further to above: I subclassed ScrollBar and passed in the ScrollViewer I wanted to bind. Seems to work ok.

    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;
            }
        }
    }