Synchronized scrolling of two ScrollViewers whenever any one is scrolled in wpf

前端 未结 5 1765
长情又很酷
长情又很酷 2020-11-27 05:48

I have gone through the thread:

binding two VerticalScrollBars one to another

it has almost helped to achieve the goal but still there is something missing.

5条回答
  •  天涯浪人
    2020-11-27 06:25

    Well, I made an implementation based on https://www.codeproject.com/Articles/39244/Scroll-Synchronization but it's I think neater.

    There's a synchronised scroll token that holds references to the things to scroll. Then there's the attached property that is separate. I haven't figured out how to unregister because the reference remains - so I left that unimplemented.

    Eh, here goes:

    public class SynchronisedScroll
    {
    
        public static SynchronisedScrollToken GetToken(ScrollViewer obj)
        {
            return (SynchronisedScrollToken)obj.GetValue(TokenProperty);
        }
        public static void SetToken(ScrollViewer obj, SynchronisedScrollToken value)
        {
            obj.SetValue(TokenProperty, value);
        }
        public static readonly DependencyProperty TokenProperty =
            DependencyProperty.RegisterAttached("Token", typeof(SynchronisedScrollToken), typeof(SynchronisedScroll), new PropertyMetadata(TokenChanged));
    
        private static void TokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var scroll = d as ScrollViewer;
            var oldToken = e.OldValue as SynchronisedScrollToken;
            var newToken = e.NewValue as SynchronisedScrollToken;
    
            if (scroll != null)
            {
                oldToken?.unregister(scroll);
                newToken?.register(scroll);
            }
        }
    }
    

    and the other bit

    public class SynchronisedScrollToken
    {
        List registeredScrolls = new List();
    
        internal void unregister(ScrollViewer scroll)
        {
            throw new NotImplementedException();
        }
    
        internal void register(ScrollViewer scroll)
        {
            scroll.ScrollChanged += ScrollChanged;
            registeredScrolls.Add(scroll);
        }
    
        private void ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            var sendingScroll = sender as ScrollViewer;
            foreach (var potentialScroll in registeredScrolls)
            {
                if (potentialScroll == sendingScroll)
                    continue;
    
                if (potentialScroll.VerticalOffset != sendingScroll.VerticalOffset)
                    potentialScroll.ScrollToVerticalOffset(sendingScroll.VerticalOffset);
    
                if (potentialScroll.HorizontalOffset != sendingScroll.HorizontalOffset)
                    potentialScroll.ScrollToHorizontalOffset(sendingScroll.HorizontalOffset);
            }
        }
    }
    

    Use by defining a token in some resource accessible to all the things that need to be scroll synchronised.

    
    

    And then use it wherever you need it by:

    
        
    
    

    I've only tested it when scrolling vertically and it works for me.

提交回复
热议问题