zoukankan      html  css  js  c++  java
  • 不修改模板的前提下修改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

  • 相关阅读:
    Angularjs总结(一)表单验证
    list集合中指定字段去重
    NodeJS学习笔记—2.AMD规范
    NodeJS学习笔记—1.CommonJS规范
    WCF上传、下载、删除文件
    .net RAW(16)与GUID互相转换
    Angularjs总结(六) 上传附件
    可以打开mdb文件的小软件
    数据库导出导入操作(expdp,impdp)
    用Ueditor存入数据库带HTML标签的文本,从数据库取出来后,anjular用ng-bind-html处理带HTML标签的文本
  • 原文地址:https://www.cnblogs.com/blue-fire/p/10009139.html
Copyright © 2011-2022 走看看