wpf
Animation 페이지 넘기기 컨트롤
동동(이재동)
2016. 4. 6. 13:47
페이지가 여러개 있을때 페이지 넘기는 효과를 준다. 여러가지 type이 있다.ContentTemplateSelector가 변경되었을때 이벤트를 이용하기때문에 TempleteSelector를 만들어야 한다.샘플 파일사용법 Xaml<local:AnimatedContentControl AnimationDuration="0:0:1.0" Content="{Binding NavigationState}" AnimateType="Right" Height="200" ContentTemplateSelector="{DynamicResource MainTemplateSelector}"></local:AnimatedContentControl>TemplateSelector.cspublic class MainTemplateSelector : DataTemplateSelector{public DataTemplate TestTemplate { get; set; }public DataTemplate LoadingTemplate { get; set; }public MainTemplateSelector(){}public override DataTemplate SelectTemplate(object item, DependencyObject container){if ((item as string) == "Loading"){return LoadingTemplate;}else{return TestTemplate;}return base.SelectTemplate(item, container);}}AnimationContentControl.cspublic enum AnimateType{Right,Top,Down,Left,Opacity,}/// <summary>/// A ContentControl that animates the transition between content/// </summary>[TemplatePart(Name = "PART_PaintArea", Type = typeof(Shape)),TemplatePart(Name = "PART_MainContent", Type = typeof(ContentPresenter))]public class AnimatedContentControl : ContentControl{public AnimateType AnimateType{get { return (AnimateType)GetValue(AnimateTypeProperty); }set { SetValue(AnimateTypeProperty, value); }}// Using a DependencyProperty as the backing store for AnimateType. This enables animation, styling, binding, etc...public static readonly DependencyProperty AnimateTypeProperty =DependencyProperty.Register("AnimateType", typeof(AnimateType), typeof(AnimatedContentControl), new PropertyMetadata(AnimateType.Left));#region Generated static constructorstatic AnimatedContentControl(){DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedContentControl), new FrameworkPropertyMetadata(typeof(AnimatedContentControl)));}#endregion Generated static constructorpublic TimeSpan AnimationDuration{get { return (TimeSpan)GetValue(AnimationDurationProperty); }set { SetValue(AnimationDurationProperty, value); }}// Using a DependencyProperty as the backing store for AnimationDuration. This enables animation, styling, binding, etc...public static readonly DependencyProperty AnimationDurationProperty =DependencyProperty.Register("AnimationDuration", typeof(TimeSpan), typeof(AnimatedContentControl), new PropertyMetadata(TimeSpan.FromSeconds(0.5)));public IEasingFunction EasingFunction{get { return (IEasingFunction)GetValue(EasingFunctionProperty); }set { SetValue(EasingFunctionProperty, value); }}// Using a DependencyProperty as the backing store for EasingFunction. This enables animation, styling, binding, etc...public static readonly DependencyProperty EasingFunctionProperty =DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(AnimatedContentControl), new PropertyMetadata(new PowerEase() { EasingMode = EasingMode.EaseInOut }));private Shape m_paintArea;private ContentPresenter m_mainContent;/// <summary>/// This gets called when the template has been applied and we have our visual tree/// </summary>public override void OnApplyTemplate(){m_paintArea = Template.FindName("PART_PaintArea", this) as Shape;m_mainContent = Template.FindName("PART_MainContent", this) as ContentPresenter;base.OnApplyTemplate();}protected override void OnContentTemplateSelectorChanged(DataTemplateSelector oldContentTemplateSelector, DataTemplateSelector newContentTemplateSelector){base.OnContentTemplateSelectorChanged(oldContentTemplateSelector, newContentTemplateSelector);if (ContentTemplateSelector != null){ContentTemplate = ContentTemplateSelector.SelectTemplate(Content, null);}}protected override void OnContentTemplateChanged(DataTemplate oldContentTemplate, DataTemplate newContentTemplate){base.OnContentTemplateChanged(oldContentTemplate, newContentTemplate);}/// <summary>/// This gets called when the content we're displaying has changed/// </summary>/// <param name="oldContent">The content that was previously displayed</param>/// <param name="newContent">The new content that is displayed</param>protected override void OnContentChanged(object oldContent, object newContent){if (m_paintArea != null && m_mainContent != null){m_paintArea.Fill = CreateBrushFromVisual(m_mainContent);BeginAnimateContentReplacement();}if (ContentTemplateSelector != null){ContentTemplate = ContentTemplateSelector.SelectTemplate(newContent, null);}base.OnContentChanged(oldContent, newContent);}/// <summary>/// Starts the animation for the new content/// </summary>private void BeginAnimateContentReplacement(){var newContentTransform = new TranslateTransform();var oldContentTransform = new TranslateTransform();m_paintArea.RenderTransform = oldContentTransform;m_mainContent.RenderTransform = newContentTransform;m_paintArea.Visibility = Visibility.Visible;switch (AnimateType){case AnimateType.Top:newContentTransform.BeginAnimation(TranslateTransform.YProperty, CreateAnimation(-this.ActualHeight, 0));oldContentTransform.BeginAnimation(TranslateTransform.YProperty, CreateAnimation(0, this.ActualHeight, (s, e) => m_paintArea.Visibility = Visibility.Hidden));break;case AnimateType.Down:newContentTransform.BeginAnimation(TranslateTransform.YProperty, CreateAnimation(this.ActualHeight, 0));oldContentTransform.BeginAnimation(TranslateTransform.YProperty, CreateAnimation(0, -this.ActualHeight, (s, e) => m_paintArea.Visibility = Visibility.Hidden));break;case AnimateType.Left:newContentTransform.BeginAnimation(TranslateTransform.XProperty, CreateAnimation(-this.ActualWidth, 0));oldContentTransform.BeginAnimation(TranslateTransform.XProperty, CreateAnimation(0, this.ActualWidth, (s, e) => m_paintArea.Visibility = Visibility.Hidden));break;case AnimateType.Right:newContentTransform.BeginAnimation(TranslateTransform.XProperty, CreateAnimation(this.ActualWidth, 0));oldContentTransform.BeginAnimation(TranslateTransform.XProperty, CreateAnimation(0, -this.ActualWidth, (s, e) => m_paintArea.Visibility = Visibility.Hidden));break;case AnimateType.Opacity:m_mainContent.BeginAnimation(UIElement.OpacityProperty, CreateAnimation(0, 1));m_paintArea.BeginAnimation(UIElement.OpacityProperty, CreateAnimation(1, 0, (s, e) => m_paintArea.Visibility = Visibility.Hidden));break;default:break;}}/// <summary>/// Creates the animation that moves content in or out of view./// </summary>/// <param name="from">The starting value of the animation.</param>/// <param name="to">The end value of the animation.</param>/// <param name="whenDone">(optional) A callback that will be called when the animation has completed.</param>private AnimationTimeline CreateAnimation(double from, double to, EventHandler whenDone = null){var anim = new DoubleAnimation(from, to, AnimationDuration) { EasingFunction = EasingFunction };if (whenDone != null)anim.Completed += whenDone;anim.Freeze();return anim;}/// <summary>/// Creates a brush based on the current appearnace of a visual element. The brush is an ImageBrush and once created, won't update its look/// </summary>/// <param name="v">The visual element to take a snapshot of</param>private Brush CreateBrushFromVisual(Visual v){if (v == null)throw new ArgumentNullException("v");var target = new RenderTargetBitmap((int)this.ActualWidth, (int)this.ActualHeight, 96, 96, PixelFormats.Pbgra32);target.Render(v);var brush = new ImageBrush(target) { AlignmentY = AlignmentY.Top, Stretch = Stretch.None };brush.Freeze();return brush;}}