原文连接:不修改模板的前提下修改VisualState中的某些值 - 超威蓝火html
UWP里有一件很是使人不爽的事,大部分控件只提供了Normal状态下的Background,Foreground,BorderBrush,而控件通常至少具备Normal、PointerOver、Pressed、Disabled,ItemContainerStyle还有Selected、PointerOverSelected、PressedSelected这几种。那么常规方法怎么修改这几个状态内的值呢?
固然是贴一遍又臭又长的Style。
那若是有不少不是很同样的控件,除了修改模板或者自定义一个控件以外,有没有办法修改状态内的值呢?
答案是确定的。咱们能够经过某些方法拿到VisualStateGroup对象,而后操做里面的Storyboard。
首先咱们须要一个获取VisualStateGroup的方法,这玩意儿藏在Style中的Template中的第一个子元素里,而这个子元素会在须要的元素ApplyTemplate后,经过当猴子(爬树)获得:git
public static Task<VisualStateGroup> GetCommonStates(this FrameworkElement element) { var vGroup = VisualStateManager.GetVisualStateGroups(element)?.FirstOrDefault(x => x.Name == "CommonStates"); var resultSource = new TaskCompletionSource<VisualStateGroup>(); if (vGroup == null) { if (element.GetFirstChild() is FrameworkElement ele) { element = ele; vGroup = VisualStateManager.GetVisualStateGroups(element)?.FirstOrDefault(x => x.Name == "CommonStates"); } else if (!element.IsLoaded()) { void Element_Loaded(object sender, RoutedEventArgs e) { element.Loaded -= Element_Loaded; vGroup = VisualStateManager.GetVisualStateGroups(element)?.FirstOrDefault(x => x.Name == "CommonStates"); if (vGroup == null) { if (element.GetFirstChild() is FrameworkElement ele2) { element = ele2; vGroup = VisualStateManager.GetVisualStateGroups(element)?.FirstOrDefault(x => x.Name == "CommonStates"); } } resultSource.SetResult(vGroup); } element.Loaded += Element_Loaded; } else { return null; } } else { resultSource.SetResult(vGroup); } return resultSource.Task; }
这是一个老问题,在设置附加属性的时候,元素可能并无加载完,这时候是没有第一个子元素的,因此要用一个内部方法或者内部的RouteEventHandler挂到Loaded上去获取。内部是由于要共享变量,并且要在进入Loaded事件以后卸载掉这个方法。
接下来咱们要从CommonStates中获取Pressed和PointerOver这两个State:github
var commonStates = await ele.GetCommonStates(); if (commonStates != null) { var storyboard = commonStates.States.FirstOrDefault(x => x.Name == "PointerOver")?.Storyboard; if (storyboard != null) { var list = storyboard.Children.Where(x => BackgroundNames.Contains(Storyboard.GetTargetName(x).ToLowerInvariant()) && Storyboard.GetTargetProperty(x) == "Background"); foreach (var item in list) { item.SetAnimationValue(a.NewValue); } } }
这样就大功告成了。
使用方法以下:this
xmlns:helper="using:PointerStateHelper.Helpers" <Button HorizontalAlignment="Center" VerticalAlignment="Center" helper:PointerOverHelper.Background="Red" helper:PointerOverHelper.Foreground="Blue" helper:PointerOverHelper.BorderBrush="Transparent" helper:PressedHelper.Background="Green" helper:PressedHelper.Foreground="Gray" helper:PressedHelper.BorderBrush="Transparent" Content="哈哈哈" Padding="20,10" />