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) ) );
- UIPropertyMetadata,的几个参数:
public UIPropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);
进行附加依赖项属性设置时,有三个步骤:
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,结果展示