不修改模板的前提下修改VisualState中的某些值

栏目: IOS · 发布时间: 5年前

内容简介:UWP里有一件非常令人不爽的事,大部分控件只提供了Normal状态下的Background,Foreground,BorderBrush,而控件一般至少具有Normal、PointerOver、Pressed、Disabled,ItemContainerStyle还有Selected、PointerOverSelected、PressedSelected这几种。那么常规方法怎么修改这几个状态内的值呢?当然是贴一遍又臭又长的Style。那如果有很多不是很一样的控件,除了修改模板或者自定义一个控件之外,有没有

UWP里有一件非常令人不爽的事,大部分控件只提供了Normal状态下的Background,Foreground,BorderBrush,而控件一般至少具有Normal、PointerOver、Pressed、Disabled,ItemContainerStyle还有Selected、PointerOverSelected、PressedSelected这几种。那么常规方法怎么修改这几个状态内的值呢?

当然是贴一遍又臭又长的Style。

那如果有很多不是很一样的控件,除了修改模板或者自定义一个控件之外,有没有办法修改状态内的值呢?

答案是肯定的。我们可以通过某些方法拿到VisualStateGroup对象,然后操作里面的Storyboard。

首先我们需要一个获取VisualStateGroup的方法,这玩意儿藏在Style中的Template中的第一个子元素里,而这个子元素会在需要的元素ApplyTemplate后,通过当猴子(爬树)得到:

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:

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);
         }
     }
 }

这样就大功告成了。

使用方法如下:

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" />

github: https://github.com/cnbluefire/PointerStateHelper


以上所述就是小编给大家介绍的《不修改模板的前提下修改VisualState中的某些值》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML5与CSS3基础教程(第7版)

HTML5与CSS3基础教程(第7版)

[美] Elizabeth Castro、[美] Bruce Hyslop / 望以文 / 人民邮电出版社 / 2013-1 / 59.00元

代表下一代网页编写技术的HTML5,为网页提供布局和格式的CSS3,这两者构成了Web开发的基石,也是Web程序员和设计师必须熟练掌握的最基本技能。 本书是风靡全球的HTML和CSS最佳入门教程的最新版,上一版单单英文版的销量就超过100万册,被翻译为十多种语言,并长期雄踞亚马逊书店计算机图书排行榜榜首。 最新的第7版秉承前一版直观、透彻、全面、循序渐进的讲授特色,仍然采用独特的双栏图......一起来看看 《HTML5与CSS3基础教程(第7版)》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试