using System; |
using System.Windows; |
using System.Windows.Controls; |
using System.Windows.Input; |
using System.Windows.Media; |
using System.Windows.Media.Animation; |
|
namespace Telerik.Windows.QuickStart |
{ |
[TemplatePart(Name = "ScrollViewer", Type = typeof(ScrollViewer))] |
public class AutoScrollPanel : ContentControl |
{ |
#region - private fields - |
private FrameworkElement content { get; set; } |
private string PROPERTY_NAME = "(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)"; |
private Point currentMousePosition = new Point(); |
private ScrollViewer scrollViewer; |
private double CurrentTransformY |
{ |
get |
{ |
return ((content.RenderTransform as TransformGroup).Children[0] as TranslateTransform).Y; |
} |
set |
{ |
((content.RenderTransform as TransformGroup).Children[0] as TranslateTransform).Y = value; |
} |
} |
#endregion |
|
public AutoScrollPanel() |
{ |
this.DefaultStyleKey = typeof(AutoScrollPanel); |
Loaded += (sender, e) => { InitializeComponent(); }; |
} |
|
public override void OnApplyTemplate() |
{ |
base.OnApplyTemplate(); |
|
scrollViewer = this.GetTemplateChild("ScrollViewer") as ScrollViewer; |
} |
|
private void InitializeComponent() |
{ |
content = this.Content as FrameworkElement; |
|
content.RenderTransform = CreateTransformGroup(); |
} |
|
private static TransformGroup CreateTransformGroup() |
{ |
var transformGroup = new TransformGroup(); |
transformGroup.Children.Add(new TranslateTransform()); |
return transformGroup; |
} |
|
|
protected override void OnMouseMove(MouseEventArgs e) |
{ |
base.OnMouseMove(e); |
|
currentMousePosition = e.GetPosition(scrollViewer); |
|
double newIndex = CreateNewTransformY(); |
|
var storyBoard = new CustomStoryboard(content); |
SetStoryBoard(this, storyBoard); |
|
EasingValues easingValues = CreateEasingValues(newIndex); |
|
var doubleAnimation = new DoubleAnimationUsingKeyFrames(); |
var k1 = new LinearDoubleKeyFrame |
{ |
KeyTime = TimeSpan.FromMilliseconds(200), |
Value = easingValues.EasingOne |
}; |
|
var k2 = new LinearDoubleKeyFrame |
{ |
KeyTime = TimeSpan.FromMilliseconds(500), |
Value = easingValues.EasingTwo |
}; |
|
var k3 = new LinearDoubleKeyFrame |
{ |
KeyTime = TimeSpan.FromMilliseconds(1000), |
Value = -newIndex |
}; |
|
doubleAnimation.KeyFrames.Add(k1); |
doubleAnimation.KeyFrames.Add(k2); |
doubleAnimation.KeyFrames.Add(k3); |
|
storyBoard.AddAnimationTimeline(PROPERTY_NAME, doubleAnimation); |
storyBoard.StartAnimation(this); |
} |
|
|
private int CreateNewTransformY() |
{ |
// invisible size of the content in the scrollviewer |
double scrollableHeight = scrollViewer.ScrollableHeight; |
|
// visible height of the content in scrollviewer |
double viewPortHeight = scrollViewer.ViewportHeight; |
|
double index = currentMousePosition.Y / viewPortHeight; |
|
return (int)Math.Round(index * scrollableHeight); |
} |
|
private EasingValues CreateEasingValues(double destinationPoint_Y) |
{ |
EasingValues values = new EasingValues(); |
|
// Calculate the middle values from beggining and and of the animaiton |
double v1 = (CurrentTransformY + destinationPoint_Y) / 3; |
|
values.EasingOne = CurrentTransformY - v1; |
values.EasingTwo = CurrentTransformY - (v1 * 2); |
|
return values; |
} |
|
protected override void OnMouseLeave(MouseEventArgs e) |
{ |
base.OnMouseLeave(e); |
|
//StopAnimation(); |
} |
|
internal void UpdatePosition() |
{ |
StopAnimation(); |
|
double newIndex = CreateNewTransformY(); |
|
CurrentTransformY = -newIndex; |
} |
|
public void StopAnimation() |
{ |
var storyBoard = GetStoryBoard(this); |
if (null != storyBoard && !storyBoard.IsFinished) |
{ |
storyBoard.Pause(); |
} |
} |
|
#region - Attached properties - |
|
public static CustomStoryboard GetStoryBoard(DependencyObject obj) |
{ |
return (CustomStoryboard)obj.GetValue(StoryBoardProperty); |
} |
|
public static void SetStoryBoard(DependencyObject obj, CustomStoryboard value) |
{ |
obj.SetValue(StoryBoardProperty, value); |
} |
|
public static readonly DependencyProperty StoryBoardProperty = |
DependencyProperty.RegisterAttached("StoryBoard", typeof(CustomStoryboard), typeof(AutoScrollPanel), null); |
|
#endregion |
} |
|
internal class EasingValues |
{ |
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
public double EasingOne { get; set; } |
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
public double EasingTwo { get; set; } |
} |
} |
|