首页 > 其他分享 >MAUI新生5.3-样式外观:触发器Trigger

MAUI新生5.3-样式外观:触发器Trigger

时间:2022-12-18 14:11:33浏览次数:40  
标签:触发 触发器 5.3 Invoke 控件 状态 Trigger MAUI 属性

MAUI的触发器,提供了在运行时动态更改控件样式的方法。在Blazor或Vue中,可以通过三元表达式或绑定class来轻松实现,而MAUI则相对麻烦些,需要通过触发器来实现。触发器,其实就是控件的一个属性,只要是可视化控件,都带有一个Triggers集合属性,在这个集合属性中,可以设置多个Trigger。Trigger包括两个组成部分,一是触发条件,二是改变目标(样式类属性及其值)。对触发条件来说,我们有时候需要某个属性或数据改变时就触发,或者直接用事件触发,还或者当控件状态发生改变时触发,MAUI相应为我们提供的属性触发器、数据触发器、事件触发器和状态触发器。而需要改变的样式类属性,大多数时候是通过Setter,当然也可以通过后台代码。 


一、属性触发器Trigger

<!--属性触发器:直接在控件中定义=================================================================-->
<ContentPage
    ......>
    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry Placeholder="请输入">
            <Entry.Triggers>
                <!--触发条件:当Entry的属性IsFocused的值为true时。-->
                <Trigger TargetType="Entry" Property="IsFocused" Value="True" >
                    <!--在Trigger的Setters集合属性中设置Setter,<Trigger.Setters>可以省略-->
                    <!--当触发条件达到时,Entry的背景颜色变为AliceBlue-->
                    <Trigger.Setters>
                        <Setter Property="BackgroundColor" Value="AliceBlue"/>
                    </Trigger.Setters>
                </Trigger>
            </Entry.Triggers>
        </Entry>
    </StackLayout>
</ContentPage>

<!--属性触发器:通过资源字典中的样式定义触发器,效果以上例一样========================================-->
<ContentPage
    ......>
    <!--在资源字典中定义样式触发器,隐式应用于Entry控件-->
    <ContentPage.Resources>
        <Style TargetType="Entry">
            <Style.Triggers>
                <!--Trigger的定义,和在控件中定义一模一样-->
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="BackgroundColor" Value="AliceBlue" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ContentPage.Resources>
    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry Placeholder="请输入" />
    </StackLayout>
</ContentPage>

 

 


二、数据触发器DataTrigger

<ContentPage
    ......>
    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry x:Name="entry" Placeholder="请输入" />
        <Button Text="确定">
            <Button.Triggers>
                <!--  数据触发器的类型为DataTrigger  -->
                <!--  通过Binding,绑定数据,数据源可以是当前页面的UI属性值,也可以是后台属性。也可以使用Converter  -->
                <DataTrigger
                    Binding="{Binding Source={x:Reference entry}, Path=Text.Length}"
                    TargetType="Button"
                    Value="10">
                    <!--设置了多个Setter,可以触发多个属性的变更-->
                    <Setter Property="IsEnabled" Value="False" />
                    <Setter Property="BackgroundColor" Value="Red" />
                </DataTrigger>
            </Button.Triggers>
        </Button>
    </StackLayout>
</ContentPage>

 



三、属性和数据触发器的多触发条件MultiTrigger

  • 触发器可以触发多个属性的变更,也可以通过<MultiTrigger>和<MultiTrigger.Conditions>设置多触发条件。
  • 设置多触发条件时,必须所有条件都满足,才会触发
  • 只有属性和数据触发器,可以设置多条件。数据使用BindingCondition,属性使用PropertyCondition
<ContentPage
    ......>
    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry x:Name="entry1" Placeholder="请输入email" Text=""/>
        <Entry x:Name="entry2" Placeholder="请输入phone" Text=""/>
        <Button Text="确定">
            <Button.Triggers>
                <!--单触发条件使用Trigger,多触发条件使用MultiTrigger-->
                <MultiTrigger TargetType="Button">
                    <!--设置多触发条件-->
                    <MultiTrigger.Conditions>
                        <!--通过BindingCondition设置多个数据触发条件-->
                        <BindingCondition Binding="{Binding Source={x:Reference entry1},Path=Text.Length}" Value="10"/>
                        <BindingCondition Binding="{Binding Source={x:Reference entry2},Path=Text.Length}" Value="10"/>
                        <!--也可以设置多个属性触发条件,如-->
                        <PropertyCondition Property="Text" Value="确定"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="IsEnabled" Value="False"/>
                </MultiTrigger>
            </Button.Triggers>
        </Button>
    </StackLayout>
</ContentPage>

 

 

四、属性和数据触发器的EnterActions和ExitActions

  • 通过后台代码更改目标属性,如:<Trigger.EnterActions><local:FadeTriggerAction StartsFrom="0" /></Trigger.EnterActions>
  • 当满足触发条件时,将执行上例中,FadeTriggerAction对象的Invoke方法,在这个方法中,可以更改控件属性
  • FadeTriggerAction是TriggerAction<T>类的派生类,T为目标控件的类型,这个类中重写Invoke方法
<!--使用属性触发器的EnterActions和ExitActions-->
<ContentPage
    ......
    xmlns:triggeraction="clr-namespace:MauiApp12.TriggerActions">

    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry x:Name="entry" Placeholder="请输入" Text="">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <!--
                    ①当聚焦条件满足(EnterActions)或不满足(ExitActions)时,创建立FadeTriggerAction对象,初始化StartsFrom属性
                    ②执行FadeTriggerAction对象的Invoke方法
                    ③本案例中,FadeTriggerAction对象的Invoke方法,将创建一个背景色的渐变动画
                    -->
                    <Trigger.EnterActions>
                        <triggeraction:FadeTriggerAction StartsFrom="0"/>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <triggeraction:FadeTriggerAction StartsFrom="1"/>
                    </Trigger.ExitActions>
                </Trigger>
            </Entry.Triggers>
        </Entry>
        
    </StackLayout>
</ContentPage>

<!--定义EnterActions和ExitActions-->
<!--在TriggerActions文件夹中定义FadeTriggerAction类,派生自TriggerAction<T>-->
public class FadeTriggerAction : TriggerAction<VisualElement>
{
    //StartsFrom属性值,在创建FadeTriggerAction对象时初始化
    public int StartsFrom { get; set; }
    //重写Invoke方法,参数sender为触发器的宿主控件
    protected override void Invoke(VisualElement sender)
    {
        //设置sender的Animate,自定义一个背景色渐变动画
        sender.Animate("FadeTriggerAction",new Animation((d) =>
        {
            var val = StartsFrom == 1 ? d : 1-d;
            sender.BackgroundColor = Color.FromRgb(1, val, 1);
        }),
        length:1000, //动画长度1000毫秒
        easing:Easing.Linear); //动画的速率-恒定速度
    }
}

 

 

五、事件触发器

  • 事件触发器的使用,和属性/数据触发器的EnterAcitons/ExitActions用法类似,都是调用TriggerAction<T>派生类对象的Invoke方法,在后台代码中更改控件的样式属性
  • 事件触发器不能使用EnterAcitons/ExitActions,也不能使用Setter
//XAML文件中定义事件触发器=========================================================================================
<ContentPage
    ......
    xmlns:triggeraction="clr-namespace:MauiApp12.TriggerActions">
    <StackLayout x:Name="stackLayout" Padding="10">
        <Entry x:Name="entry" Placeholder="请输入" Text="">
            <Entry.Triggers>
                //在Triggers集合中,增加EventTrigger事件触发器
                <EventTrigger Event="TextChanged">
                    //当TextChanged事件发生时,调用NumericValidationTriggerAction对象的Invoke方法
                    //NumericValidationTriggerAction是TriggerAction<T>的派生类
                    <triggeraction:NumericValidationTriggerAction/>
                </EventTrigger>
            </Entry.Triggers>
        </Entry>
    </StackLayout>
</ContentPage>


//在后台代码中,更改控件的样式属性==================================================================================
//和EnterAcitons/ExitAcitons的用法一样,派生自泛型抽像类TriggerAction<T>,泛型参数为宿主类型
//重写抽像类的Invoke方法,但满足触发条件时(此例为Entry的TextChanged事件),调用Invoke方法
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
    protected override void Invoke(Entry entry)
    {
        //尝试将输入值转换为double,如果可以转,则将转化成功后的值赋值给result,并返回true,否则返回false
        double result;
        bool isValid = Double.TryParse(entry.Text,out result); 
        //如果可以转(说明是数值),则entry的字体颜色为黑色,否则为红色
        entry.TextColor = isValid ? Colors.Black : Colors.Red;
    }
}

 



六、状态触发器:

  • 回顾控件状态章节,当我们自定义状态时,需要在后台代码中调用VisualStateManager.GoToState方法,来定义控件状态改变的逻辑。而使用触发器,可以直接在XAML文件中,通过触发器来触发控件状态的变更。当符合某个触发条件时,控件转到某个状态,使用更加方便。
  • 每个控件状态VisualState,有一个VisualState.StateTriggers集合属性,将触发器添加到这个集合中。
  • 触发器的触发条件,包括:绑定数据、绑定属性、窗口大小、设备类型、设备方向等。
  • 每个状态触发器,还有一个IsActiveChanged事件,当满足触发条件时,还可以执行这个事件的委托方法。

 

1、状态触发器:数据触发

<ContentPage
    ......>
    <ContentPage.Resources>
        <!--定义隐式样式,自动作用于Grid控件-->
        <Style TargetType="Grid">
            <!--设置附加属性VisualStateManager.VisualStateGroups,和控件状态的使用基本一样-->    
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <!--为Grid自定义了两个状态,Checked和UnChecked-->
                    <VisualStateGroup>
                        <VisualState x:Name="Checked">
                            <!--定义状态触发器,使用绑定数据的方式,IsToggled可以通过MVVM模式,绑定ViewModel的数据-->
                            <!--同时,在触发器上定义了IsActiveChanged事件的事件处理程序OnCheckedStateIsActiveChanged-->
                            <VisualState.StateTriggers>
                                <StateTrigger IsActive="{Binding IsToggled}"
                                      IsActiveChanged="OnCheckedStateIsActiveChanged" />
                            </VisualState.StateTriggers>
                            <!--状态的Setters设置,详见控件状态章节-->
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor"
                                Value="Black" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Unchecked">
                            <VisualState.StateTriggers>
                                <StateTrigger IsActive="{Binding IsToggled, Converter={StaticResource inverseBooleanConverter}}"
                                      IsActiveChanged="OnUncheckedStateIsActiveChanged" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor"
                                Value="White" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>
    </ContentPage.Resources>
<Grid RowDefinitions="1*,2*,Auto" ColumnDefinitions="1*,1*,Auto"> ...... </Grid> </ContentPage>

 

 

2、状态触发器:属性触发

<ContentPage
    ......>
    <ContentPage.Resources>
        <Style TargetType="Grid">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup>
                        <!--自定义了两个控件状态,Checked和Unchecked-->
                        <VisualState x:Name="Checked">
                            <!--  定义触发器,使用绑定控件属性的方式  -->
                            <!--  StateTrigger和CompareStateTrigger,都派生自StateTriggerBase,也可以使用IsActiveChanged事件  -->
                            <!--CompareStateTrigger绑定当前页面的checkBox控件的IsChecked属性,当值为True时触发控件状态Checked-->
                            <VisualState.StateTriggers>
                                <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}" Value="True" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor" Value="Black" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Unchecked">
                            <!--CompareStateTrigger绑定当前页面的checkBox控件的IsChecked属性,当值为False时触发控件状态Checked-->
                            <VisualState.StateTriggers>
                                <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}" Value="False" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor" Value="White" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>
    </ContentPage.Resources>

    <Grid>
        <StackLayout Orientation="Horizontal">
            <CheckBox x:Name="checkBox" VerticalOptions="Center" />
            <Label Text="点击复选框,改变Grid的背景色" VerticalOptions="Center" />
        </StackLayout>
    </Grid>
</ContentPage>

 

3、状态触发器:窗口大小触发

<ContentPage
    ......>
    <ContentPage.Resources>
        <Style TargetType="StackLayout">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <!--定义两个状态,状态Vertical,StackLayout的方向为Vertical。状态Horizontal,StackLayout的为Horizontal-->
                    <!--触发器为AdaptiveTrigger,触发条件为窗口大小,通过设置MinWindowWidth和MinWindowHeight-->
                    <!--MinWindowWidth和MinWindowHeight的使用逻辑,和CSS中的媒体查询类似-->
                    <VisualStateGroup>
                        <VisualState x:Name="Vertical">
                            <VisualState.StateTriggers>
                                
                                <AdaptiveTrigger MinWindowWidth="0" MinWindowHeight="0"/>
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="Orientation"
                                Value="Vertical" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Horizontal">
                            <VisualState.StateTriggers>
                                <AdaptiveTrigger MinWindowWidth="800" MinWindowHeight="800"/>
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="Orientation"
                                Value="Horizontal" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>
    </ContentPage.Resources>

    <StackLayout>
        <!--定义三个测试的盒子-->
        <Label Text="111" WidthRequest="100" HeightRequest="100" BackgroundColor="Red"/>
        <Label Text="222" WidthRequest="100" HeightRequest="100" BackgroundColor="Yellow"/>
        <Label Text="333" WidthRequest="100" HeightRequest="100" BackgroundColor="Green"/>
    </StackLayout>
</ContentPage>

 

4、状态触发器:设备类型触发

<!--通过DeviceStateTrigger,设置设备类型触发器-->
<!--目前支持的类型包括iOS、Android、WinUI、MacCatalyst、Tizen-->
<VisualState.StateTriggers>
    <DeviceStateTrigger Device="iOS" />
</VisualState.StateTriggers>

 

5、状态触发器:设备方向触发

 

<!--通过OrientationStateTrigger,设置设备方向触发器-->
<!--目前支持的方向包括Portrait(竖屏)、Landscape(横屏)-->
<VisualState.StateTriggers>
    <OrientationStateTrigger Orientation="Portrait" />
</VisualState.StateTriggers>

 

标签:触发,触发器,5.3,Invoke,控件,状态,Trigger,MAUI,属性
From: https://www.cnblogs.com/functionMC/p/16988512.html

相关文章

  • 微软跨平台maui开发chatgpt客户端
    image什么是maui.NET多平台应用UI(.NETMAUI)是一个跨平台框架,用于使用C#和XAML创建本机移动(ios,andriod)和桌面(windows,mac)应用。imagechagpt最近......
  • 如何远程调试 MAUI blazor / Blazor Hybrid
    我们知道浏览器模式下Blazor可以使用F12打开开发工具,调试js查看页面元素,那当MauiBlazor提示烦人的anunhandlederrorhasoccurred该怎么进行调试呢?1.VS运......
  • tekton TriggerBinding资源
    公众号:什么是TriggerBinding校验事件并提取相关字段属性资源详解例子triggerBinding/binding.yamlapiVersion:triggers.tekton.dev/v1alpha1kind:TriggerBindingmetadata......
  • 环境搭建-RuntimeError: CUDA error: device-size assert triggered
    报错如下图  后经测试,发现是因为启用了混合精度训练,导致了这种异常。去掉混合精度训练的参数,--fp16就可以了。 混合精度训练需要显卡支持,30X系列的显卡会支持,显卡......
  • Quartz.net官方开发指南 第二课:Jobs And Triggers
    JobDetail对象由Quartz客户端在Job被加入到scheduler时创建。它包含了Job的各种设置属性以及一个JobDataMap对象,这个对象被用来存储给定Job类实例的状态......
  • GitLab Omnibus 更新 8.8.5 => 15.3.5
    引文虽然本意是想要从更新runner开始的,但是自装完runner之后(我直接装了最新的版本)提示只有GitLab10以后的版本才能使用,才出现接下来的一堆东西。对于这种情况的解决方案......
  • P2744 「USACO5.3」量取牛奶 Milk Measuring
    将桶按容积大小从小到大排序,令\(f_{i,j}\)表示前\(i\)个桶能否量出\(j\)夸脱,如果可以就用vector存储最优方案。先枚举桶的种类再枚举夸脱数,转移看似只有两种:之前......
  • 5.3.2 文件的实现-操作系统设计与实现(第三版)
    连续分配:缺点是在创建新文件时必须指定大小。链表分配:缺点是对文件的随机访问相当慢。因为要顺序读入前面的文件块,才能确定下一个文件块。带有文件分配表的链表结构:......
  • 5.3.1 文件系统的布局-操作系统设计与实现(第三版)5.1-5.2
    第5章文件系统5.1.2三种类型的文件字节序列、记录序列、树5.1.3可执行文件一个可执行文件有五个段:文件头、代码、数据、重定位位和符号表。文件头以所谓的魔数(magi......
  • PS/LR滤镜插件套装 Nik Collection v5.3.0 Win/Mac
    NikCollection4,其包含了八款PS插件,可提供近200种高质量的创意效果以及一系列创新的图像编辑工具,只需单击一下即可使用,同时为您提供无损编辑以实现全面控制。功能涵盖修图......