响应水龙头
切换视图的各种表现形式演示了一种响应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>