
InertiaScrollViewer – ScrollViewer com inercia!
Fevereiro 26, 2009Com este ScrollViewer temos a capacidade de fazer scroll apenas com o arrastar do rato
Updated
public class InertiaScrollViewer : ScrollViewer
{
DispatcherTimer _yourTimer;
public InertiaScrollViewer()
{
_yourTimer = new DispatcherTimer();
_yourTimer.Interval = new TimeSpan(0, 0, 0, 0, 2);
_yourTimer.Tick += new EventHandler(yourTimer_Tick);
_yourTimer.Start();
this.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
this.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
}
#region Overrides
protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
{
base.OnMouseDown(e);
InertiaScrollViewer.SetIsDragging(this, true);
InertiaScrollViewer.SetTargetX(this, e.GetPosition(this).X);
InertiaScrollViewer.SetTargetY(this, e.GetPosition(this).Y);
double offsetx = this.HorizontalOffset - e.GetPosition(this).X;
double offsety = this.VerticalOffset - e.GetPosition(this).Y;
InertiaScrollViewer.SetOffset(this, new Point(offsetx, offsety));
}
protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
{
base.OnMouseUp(e);
InertiaScrollViewer.SetTargetX(this, (e.GetPosition(this).X));
InertiaScrollViewer.SetTargetY(this, (e.GetPosition(this).Y));
InertiaScrollViewer.SetIsDragging(this, false);
}
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseLeave(e);
InertiaScrollViewer.SetIsDragging(this, false);
}
protected override void OnPreviewMouseMove(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseMove(e);
if ((InertiaScrollViewer.GetIsDragging(this) == true))
{
InertiaScrollViewer.SetTargetX(this, (e.GetPosition(this).X));
InertiaScrollViewer.SetTargetY(this, (e.GetPosition(this).Y));
}
}
#endregion
private void yourTimer_Tick(object sender, EventArgs e)
{
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
{
if (Math.Abs(Math.Round(InertiaScrollViewer.GetVelocityX(this), 3)) != 0.000)
{
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);
}
}
}
#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.96));
#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
#endregion
}
Para usar basta definir no Template que queremos usar o nosso InertiaScrollViewer
<ItemsControl>
<ItemsControl.Template>
<ControlTemplate>
<local:InertiaScrollViewer>
<StackPanel IsItemsHost="True"/>
</local:InertiaScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
Em breve vou colocar um Canvas exactamente com o mesmo funcionamento, mas para os UiElements que estão dentro dele…
Até breve,
Miguel Duarte