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


    原文链接:不修改模板的前提下修改VisualState中的某些值 - 超威蓝火

    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

  • 相关阅读:
    人在年轻的时候,最需要的能力--吃药的能力
    查分单词-Python
    关于NLP算法工程师的几点思考
    找出只出现一次的数字-Python
    最长连续序列
    二叉树中的最大路径和-Python
    windows:查找端口所对应的进程
    vue项目路由模式为history时打包后部署在nginx 配置访问
    用navicat连接数据库报错:1130-host ... is not allowed to connect to this MySql server如何处理
    mysql误删root用户
  • 原文地址:https://www.cnblogs.com/blue-fire/p/10009139.html
Copyright © 2020-2023  润新知