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

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

内容简介: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中的某些值》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

构建之法(第三版)

构建之法(第三版)

邹欣 / 人民邮电出版社 / 2017-6 / 69.00元

软件工程牵涉的范围很广, 同时也是一般院校的同学反映比较空洞乏味的课程。 但是,软件工程 的技术对于投身 IT 产业的学生来说是非常重要的。作者有在世界一流软件企业 20 年的一线软件开 发经验,他在数所高校进行了多年的软件工程教学实践,总结出了在 16 周的时间内让同学们通过 “做 中学 (Learning By Doing)” 掌握实用的软件工程技术的教学计划,并得到高校师生的积极反馈。在此 ......一起来看看 《构建之法(第三版)》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具