Fasetto.Word P12---Attached Property and Animations

1,附加的依赖性属性的建立和使用.

  • 附加依赖性属性的建立
 public static readonly DependencyProperty Value = DependencyProperty.RegisterAttached("Value",
                                                        typeof(Property),
                                                        typeof(BaseAttachedProperty<Parent, Property>),
                                                        new UIPropertyMetadata(default(Property), new PropertyChangedCallback(OnValuePropertyChanged),
                                                            new CoerceValueCallback(OnValuePropertyUpdated)
                                                            )
            );
  1. UIPropertyMetadata,的几个参数:
    public UIPropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);
      进行附加依赖项属性设置时,有三个步骤:
     image

2,创建 AnimateBaseProperty
 public class BaseAnimateAttachedProperty<Parent> : BaseAttachedProperty<Parent, bool>
        where Parent : new()
    {
        public bool FirstLoad { get; private set; } = true;

        /// <summary>
        /// when value first loaded or changed then animiate
        /// </summary>
        /// <param name="d"></param>
        /// <param name="value"></param>
        public override void OnValueUpdated(DependencyObject d, object value)
        {
            // check if it's a framework element 
            if (!(d is FrameworkElement element)) return;


            // if value is same and not first load then return
            if (element.GetValue(ValueProperty) == value && !FirstLoad) return;

            if (FirstLoad)
            {
                //  only load once track to delay do animation until the element loaded
                //because the Attached element is 
                RoutedEventHandler load = null;

                load = (ss, ee) =>
                  {
                      element.Loaded -= load;
                      FirstLoad = false;
                      DoAnimation(element, (bool)value);
                  };
                element.Loaded += load;
            }
            else
                DoAnimation(element, (bool)value);
        }

        public virtual void DoAnimation(FrameworkElement element, bool value)
        {

        }
    }
    #endregion
  • 当附加依赖项的值改变时,触发OnValueChangedUpdate,然后再触发DoAnimation
  • 当FirstLoad时,进行一个自解绑的事件绑定.

3,建立SlideInAndOutFromLeftProperty

 public class SlideInAndOutFromLeftProperty:BaseAnimateAttachedProperty<SlideInAndOutFromLeftProperty>
    {
        public override async void DoAnimation(FrameworkElement element, bool value)
        {
            if (value)
            {
                await element.SlideAndFadeInFromLeftAsync(FirstLoad?0:0.3f, false);
            }
            else
                await element.SlideAndFadeOutToLeftAsync(FirstLoad ? 0 :0.3f, false);
        }

    }
  • FirstLoad的作用是,当第一次进行动画时,一步到位.设定动画的Duration=0;

4,更新StoryHelper和Animations里面的类.

public static void AddSlideToRight(this Storyboard storyboard, float seconds, double offset, float accelerationRatio = 0.1f, bool keepMargin = true)
        {
            //Create a ThicknessAnimation
            var slideAnimation = new ThicknessAnimation
            {
                Duration = new Duration(TimeSpan.FromSeconds(seconds)),
                From = new Thickness(0),
                To = new Thickness(keepMargin ? offset : 0, 0, -offset , 0),
                AccelerationRatio = accelerationRatio,
            };

            //Bind the Ainimation and the PropertyPath"Margin"
            Storyboard.SetTargetProperty(slideAnimation, new PropertyPath("Margin"));

            //Add it to the StoryBoard
            storyboard.Children.Add(slideAnimation);
        }
  • keepMargin的作用是,当动画结束时候是否保持源控件在布局中的Margin.

5,在ApplicationViewModel中添加SlideMenuVisible.

public bool SlideMenuVisible { get; set; } = false;

6,在MainWindow.xaml中添加代码
 <!--SideMenuControl-->
            <local:SidemenuControl
                d:DataContext="{x:Null}"
                DataContext="{x:Null}"
                Width="300"
                local:SlideInAndOutFromLeftProperty.Value="{Binding ApplicationViewModel.SlideMenuVisible,Source={x:Static local:ApplicationLocator.Instance}}"
                Visibility="{Binding ApplicationViewModel.SlideMenuVisible,Source={x:Static local:ApplicationLocator.Instance},
                  Converter={local:BooleanToVisibilityConverter},ConverterParameter=True }">
                <local:ChatListControl/>
            </local:SidemenuControl>
  • 将SlideInAndOutFromLeftProperty附加属性绑定到SlideMenuVisible上,那么,当其为false,或者true的时候,调用OnvalueUpdate,就会触发相应的动画.
  • Visiblity绑定到SlideMenuVisible上面,当其为false时,不显示画面.

7,在LoginViewModel中测试代码

public async Task LoginAsycn(object parameter)
        {
            IoC.Get<ApplicationViewModel>().SlideMenuVisible ^= true;
            return;
            await RunCommand(() => LoginIsRunning, async () =>
             {
                 //body of a async work!
                 await Task.Delay(1000);
                 var email = Email;
                 SecurePassword = ((IHavePassword)parameter).SecurePassword;
                 var password = SecurePassword.Unsecure();
             });

        }

8,结果展示

imageimage

posted @ 2021-03-09 14:30  frogkiller  阅读(149)  评论(0编辑  收藏  举报