第二十三章:触发器和行为(十)

响应水龙头
切换视图的各种表现形式演示了一种响应XAML文件中的点击的方法。 如果将tap事件集成到VisualElement类中,您可以使用EventTrigger更直接且更轻松地获取它们。 但是您无法将EventTrigger附加到TapGestureRecognizer。
解决这个小限制是一种专门用于点击的行为的目的。 这叫做TapBehavior:

namespace Xamarin.FormsBook.Toolkit
{
    public class TapBehavior : Behavior<View>
    {
        TapGestureRecognizer tapGesture;
        static readonly BindablePropertyKey IsTriggeredKey =
            BindableProperty.CreateReadOnly("IsTriggered", typeof(bool),
                                            typeof(TapBehavior), false);
        public static readonly BindableProperty IsTriggeredProperty =
                                            IsTriggeredKey.BindableProperty;
        public bool IsTriggered
        {
            private set { SetValue(IsTriggeredKey, value); }
            get { return (bool)GetValue(IsTriggeredProperty); }
        }
        protected override void OnAttachedTo(View view)
        {
            base.OnAttachedTo(view);
            tapGesture = new TapGestureRecognizer();
            tapGesture.Tapped += OnTapped;
            view.GestureRecognizers.Add(tapGesture);
        }
        protected override void OnDetachingFrom(View view)
        {
            base.OnDetachingFrom(view);
            view.GestureRecognizers.Remove(tapGesture);
            tapGesture.Tapped -= OnTapped;
        }
        async void OnTapped(object sender, EventArgs args)
        {
            IsTriggered = true;
            await Task.Delay(100);
            IsTriggered = false;
        }
    }
}

TapBehavior类定义了一个名为IsTriggered的布尔属性,但它的功能与普通属性完全不同。首先,它由只读可绑定属性支持。这意味着
IsTriggered属性只能在TapBehavior类中设置,并且当IsTriggered属性在十分之一秒内变为true时,类设置IsTriggered的唯一时间是TapGestureRecognizer的事件处理程序。
换句话说,Tapped事件被转换为属性值的非常短暂的峰值 - 这让人想起事件是如何在数字硬件中触发的。但IsTriggered属性可以
然后在DataTrigger中引用。
假设您喜欢ShiverButton的想法,但是您希望将概念应用于除Button之外的其他内容,这意味着您需要响应Tapped事件。您可以使用EventTrigger,但TapBehavior允许您使用DataTrigger。
为了演示,这里是BoxViewTapShiver,它将TapBehavior对象附加到三个Box View元素,每个元素还包括一个DataTrigger,它引用行为并在其EnterActions集合中调用ShiverAction:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit=
                 "clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
             x:Class="BoxViewTapShiver.BoxViewTapShiverPage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="BoxView">
                <Setter Property="WidthRequest" Value="200" />
                <Setter Property="HeightRequest" Value="50" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout>
        <BoxView Color="Red">
            <BoxView.Behaviors>
                <toolkit:TapBehavior x:Name="tapBehavior1" />
            </BoxView.Behaviors>
            <BoxView.Triggers>
                <DataTrigger TargetType="BoxView"
                             Binding="{Binding Source={x:Reference tapBehavior1},
                                               Path=IsTriggered}"
                             Value="True">
                    <DataTrigger.EnterActions>
                        <toolkit:ShiverAction />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </BoxView.Triggers>
        </BoxView>
        <BoxView Color="Green">
            <BoxView.Behaviors>
                <toolkit:TapBehavior x:Name="tapBehavior2" />
            </BoxView.Behaviors>
            <BoxView.Triggers>
                <DataTrigger TargetType="BoxView"
                             Binding="{Binding Source={x:Reference tapBehavior2},
                                               Path=IsTriggered}"
                             Value="True">
                    <DataTrigger.EnterActions>
                        <toolkit:ShiverAction />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </BoxView.Triggers>
        </BoxView>
        <BoxView Color="Blue">
            <BoxView.Behaviors>
                <toolkit:TapBehavior x:Name="tapBehavior3" />
            </BoxView.Behaviors>
            <BoxView.Triggers>
                <DataTrigger TargetType="BoxView"
                             Binding="{Binding Source={x:Reference tapBehavior3},
                                               Path=IsTriggered}"
                             Value="True">
                    <DataTrigger.EnterActions>
                        <toolkit:ShiverAction />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </BoxView.Triggers>
        </BoxView>
    </StackLayout>
</ContentPage>

三个TapBehavior对象中的每一个都具有唯一的名称,该名称由相应的DataTrigger引用。 当您点击BoxView时,它会颤抖,并且它们都可以独立工作。
将TapBehavior和DataTrigger对象放在样式中以减少重复标记是非常诱人的,但这不起作用。 这将导致在三个BoxView元素之间共享一个TapBehavior。 此外,每个DataTrigger按名称引用相应的TapBehavior。
如果你想在这种情况下减少标记,你将再次需要定义一个新类。 ShiverViews程序演示了这一点。 它首先定义一个名为ShiverView的类,它派生自BoxView并添加TapBehavior和DataTrigger:

<BoxView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit=
                 "clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
             x:Class="ShiverViews.ShiverView">

    <BoxView.Behaviors>
        <toolkit:TapBehavior x:Name="tapBehavior" />
    </BoxView.Behaviors>
    <BoxView.Triggers>
        <DataTrigger TargetType="BoxView"
                     Binding="{Binding Source={x:Reference tapBehavior},
                                       Path=IsTriggered}"
                     Value="True">
            <DataTrigger.EnterActions>
                <toolkit:ShiverAction />
            </DataTrigger.EnterActions>
        </DataTrigger>
    </BoxView.Triggers>
</BoxView>

与SwitchClone类一样,您也可以在代码隐藏文件中添加一些属性,并在XAML文件中引用它们。
然后,ShiverViewsPage XAML文件可以使用隐式样式实例化三个独立的ShiverView对象:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ShiverViews"
             x:Class="ShiverViews.ShiverViewsPage">
    <StackLayout>
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style TargetType="local:ShiverView">
                    <Setter Property="WidthRequest" Value="200" />
                    <Setter Property="HeightRequest" Value="50" />
                    <Setter Property="HorizontalOptions" Value="Center" />
                    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                </Style>
            </ResourceDictionary>
        </StackLayout.Resources>

        <local:ShiverView Color="Red" />
        <local:ShiverView Color="Green" />
        <local:ShiverView Color="Blue" />
    </StackLayout>
</ContentPage>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章