h1

InertiaScrollViewer – ScrollViewer com inercia! (UPDATED)

Março 13, 2009

Aqui fica o novo codigo do InertiaScrollViewer, tem algumas melhorias principalmente em termos de performance.

    public class InertiaScrollViewer : ScrollViewer
    {
        DispatcherTimer _yourTimer;

        public InertiaScrollViewer()
        {

            _yourTimer = new DispatcherTimer(DispatcherPriority.Normal);
            _yourTimer.Interval = TimeSpan.FromMilliseconds(10);
            _yourTimer.Tick += new EventHandler(yourTimer_Tick);

            this.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
            this.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
        }

        #region Overrides

        protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
        {

            Point mouseposition = e.GetPosition(this);
            InertiaScrollViewer.SetIsDragging(this, true);
            InertiaScrollViewer.SetTargetX(this, mouseposition.X * -1);
            InertiaScrollViewer.SetTargetY(this, mouseposition.Y * -1);
            double offsetx = this.HorizontalOffset + mouseposition.X;
            double offsety = this.VerticalOffset + mouseposition.Y;
            InertiaScrollViewer.SetOffset(this, new Point(offsetx, offsety));
            _yourTimer.Start();
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
        {
            Point mouseposition = e.GetPosition(this);
            InertiaScrollViewer.SetTargetX(this, (mouseposition.X) * -1);
            InertiaScrollViewer.SetTargetY(this, (mouseposition.Y) * -1);
            InertiaScrollViewer.SetIsDragging(this, false);
            base.OnMouseUp(e);
        }

        protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
        {
            InertiaScrollViewer.SetIsDragging(this, false);
            base.OnMouseLeave(e);
        }

        protected override void OnPreviewMouseMove(System.Windows.Input.MouseEventArgs e)
        {
            if (!CanDrag && (InertiaScrollViewer.GetIsDragging(this) == true))
            {
                Point mouseposition = e.GetPosition(this);
                InertiaScrollViewer.SetTargetX(this, (mouseposition.X) * -1);
                InertiaScrollViewer.SetTargetY(this, (mouseposition.Y) * -1);
                _yourTimer.Start();
            }
            base.OnMouseMove(e);
        }

        #endregion

        private void yourTimer_Tick(object sender, EventArgs e)
        {

            if (!CanDrag)
            {
                this.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                this.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
                if (InertiaScrollViewer.GetIsDragging(this))
                {
                    double oldX = this.HorizontalOffset;
                    double oldY = this.VerticalOffset;

                    this.ScrollToVerticalOffset(this.VerticalOffset + (((InertiaScrollViewer.GetTargetY(this) + InertiaScrollViewer.GetOffset(this).Y) - this.VerticalOffset) * .3));
                    this.ScrollToHorizontalOffset(this.HorizontalOffset + ((InertiaScrollViewer.GetTargetX(this) + InertiaScrollViewer.GetOffset(this).X) - this.HorizontalOffset) * .3);

                    InertiaScrollViewer.SetVelocityX(this, (this.HorizontalOffset + ((InertiaScrollViewer.GetTargetX(this) + InertiaScrollViewer.GetOffset(this).X) - this.HorizontalOffset) * .3) - oldX);
                    InertiaScrollViewer.SetVelocityY(this, (this.VerticalOffset + (((InertiaScrollViewer.GetTargetY(this) + InertiaScrollViewer.GetOffset(this).Y) - this.VerticalOffset) * .3)) - oldY);
                }
                else
                {
                        this.ScrollToHorizontalOffset(this.HorizontalOffset + InertiaScrollViewer.GetVelocityX(this));
                        this.ScrollToVerticalOffset(this.VerticalOffset + InertiaScrollViewer.GetVelocityY(this));

                        InertiaScrollViewer.SetVelocityX(this, InertiaScrollViewer.GetVelocityX(this) * VelocityConst);
                        InertiaScrollViewer.SetVelocityY(this, InertiaScrollViewer.GetVelocityY(this) * VelocityConst);
                }

            }
            if ((Math.Abs(Math.Round(InertiaScrollViewer.GetVelocityX(this), 1)) == 0.0
                && Math.Abs(Math.Round(InertiaScrollViewer.GetVelocityY(this), 1)) == 0.0)
                || (this.ScrollableHeight==this.VerticalOffset && this.ScrollableWidth==this.HorizontalOffset)
                || (0 == this.VerticalOffset && 0 == this.HorizontalOffset))
            {
                _yourTimer.Stop();
                this.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
                this.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
            }
        }

        #region Properties
        #region TargetX
        public static double GetTargetX(DependencyObject obj)
        {
            return (double)obj.GetValue(TargetXProperty);
        }

        public static void SetTargetX(DependencyObject obj, double value)
        {
            obj.SetValue(TargetXProperty, value);
        }

        // Using a DependencyProperty as the backing store for TargetX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TargetXProperty =
            DependencyProperty.Register("TargetX", typeof(double), typeof(InertiaScrollViewer), new UIPropertyMetadata(0.0));

        #endregion

        #region TargetY
        public static double GetTargetY(DependencyObject obj)
        {
            return (double)obj.GetValue(TargetYProperty);
        }

        public static void SetTargetY(DependencyObject obj, double value)
        {
            obj.SetValue(TargetYProperty, value);
        }

        // Using a DependencyProperty as the backing store for TargetY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TargetYProperty =
            DependencyProperty.Register("TargetY", typeof(double), typeof(InertiaScrollViewer), new UIPropertyMetadata(0.0));

        #endregion

        #region Offset

        public static Point GetOffset(DependencyObject obj)
        {
            return (Point)obj.GetValue(OffsetProperty);
        }

        public static void SetOffset(DependencyObject obj, Point value)
        {
            obj.SetValue(OffsetProperty, value);
        }

        // Using a DependencyProperty as the backing store for Offset.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OffsetProperty =
            DependencyProperty.Register("Offset", typeof(Point), typeof(InertiaScrollViewer), new UIPropertyMetadata(new Point(0, 0)));
        #endregion

        #region Velocity

        public static double GetVelocityX(DependencyObject obj)
        {
            return (double)obj.GetValue(VelocityXProperty);
        }

        public static void SetVelocityX(DependencyObject obj, double value)
        {
            obj.SetValue(VelocityXProperty, value);
        }

        // Using a DependencyProperty as the backing store for VelocityX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VelocityXProperty =
            DependencyProperty.RegisterAttached("VelocityX", typeof(double), typeof(InertiaScrollViewer), new UIPropertyMetadata(0.0));

        public static double GetVelocityY(DependencyObject obj)
        {
            return (double)obj.GetValue(VelocityYProperty);
        }

        public static void SetVelocityY(DependencyObject obj, double value)
        {
            obj.SetValue(VelocityYProperty, value);
        }

        // Using a DependencyProperty as the backing store for VelocityY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VelocityYProperty =
            DependencyProperty.Register("VelocityY", typeof(double), typeof(InertiaScrollViewer), new UIPropertyMetadata(0.0));

        public double VelocityConst
        {
            get { return (double)GetValue(VelocityConstProperty); }
            set { SetValue(VelocityConstProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VelocityConst.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VelocityConstProperty =
            DependencyProperty.Register("VelocityConst", typeof(double), typeof(InertiaScrollViewer), new UIPropertyMetadata(0.97));

        #endregion

        #region IsDragging

        public static bool GetIsDragging(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsDraggingProperty);
        }

        public static void SetIsDragging(DependencyObject obj, bool value)
        {
            obj.SetValue(IsDraggingProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsDragging.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsDraggingProperty =
            DependencyProperty.Register("IsDragging", typeof(bool), typeof(InertiaScrollViewer), new UIPropertyMetadata(false));

        #endregion

        public bool CanDrag
        {
            get { return (bool)GetValue(CanDragProperty); }
            set { SetValue(CanDragProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CanDrag.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanDragProperty =
            DependencyProperty.Register("CanDrag", typeof(bool), typeof(InertiaScrollViewer), new UIPropertyMetadata(false));

        #endregion
    }

Até breve,
Miguel Duarte

Deixe um Comentário