しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin で Gesture と Trigger の連携を XAML で記述したい

前回 は Behavior を利用して GestureRecognizer を契機に BackgroundColor を反転させるコントロールを作りました

今回はもう少し発展させて、GestureRecognizer を契機に TriggerAction の Setter を実行するような XAML を書いてみたいと思います

修正する箇所は前回と同じ

f:id:matatabi_ux:20150118205731p:plain

まずは Behavior を修正

/// <summary>
/// GestureRecognizer に反応する Behavior
/// </summary>
public class GestureRecognizeBehavior : Behavior<View>
{
    /// <summary>
    /// アタッチされた View
    /// </summary>
    private View bindable = null;

    /// <summary>
    /// アタッチされた GestureRecognizer の BindableProperty
    /// </summary>
    public static readonly BindableProperty GestureRecognizerProperty =
        BindableProperty.Create<GestureRecognizeBehavior, TapGestureRecognizer>(p => p.GestureRecognizer, null);

    /// <summary>
    /// アタッチされた GestureRecognizer
    /// </summary>
    public TapGestureRecognizer GestureRecognizer
    {
        get { return (TapGestureRecognizer)this.GetValue(GestureRecognizerProperty); }
        set { this.SetValue(GestureRecognizerProperty, value); }
    }

    /// <summary>
    /// アタッチされた Setter のリストの BindableProperty
    /// </summary>
    public static readonly BindableProperty SettersProperty =
        BindableProperty.Create<GestureRecognizeBehavior, IList<Setter>>(p => p.Setters, new List<Setter>());

    /// <summary>
    /// アタッチされた Setter のリスト
    /// </summary>
    public IList<Setter> Setters
    {
        get { return (IList<Setter>)this.GetValue(SettersProperty); }
        set { this.SetValue(SettersProperty, value); }
    }

    /// <summary>
    /// Behavior がアタッチされた時の処理
    /// </summary>
    /// <param name="bindable">アタッチされた View</param>
    protected override void OnAttachedTo(View bindable)
    {
        base.OnAttachedTo(bindable);
        this.bindable = bindable;
        if (this.bindable == null || this.GestureRecognizer == null)
        {
            return;
        }
        this.GestureRecognizer.Tapped += this.OnGestured;
        this.bindable.GestureRecognizers.Add(this.GestureRecognizer);
    }

    /// <summary>
    /// GestureRecognizer のイベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="args">イベント引数</param>
    private void OnGestured(object sender, EventArgs args)
    {
        // アタッチされた View に Setter を反映
        foreach (var setter in this.Setters)
        {
            this.bindable.SetValue(setter.Property, setter.Value);
        }
    }

    /// <summary>
    /// Behavior がデタッチされた時の処理
    /// </summary>
    /// <param name="bindable"></param>
    protected override void OnDetachingFrom(View bindable)
    {
        if (this.bindable != null && this.GestureRecognizer != null)
        {
            this.bindable.GestureRecognizers.Remove(this.GestureRecognizer);
            this.GestureRecognizer.Tapped -= this.OnGestured;
            this.GestureRecognizer = null;
            this.bindable = null;
        }
        base.OnDetachingFrom(bindable);
    }
}

変更したのは下記の部分です

    /// <summary>
    /// アタッチされた Setter のリストの BindableProperty
    /// </summary>
    public static readonly BindableProperty SettersProperty =
        BindableProperty.Create<GestureRecognizeBehavior, IList<Setter>>(p => p.Setters, new List<Setter>());

    /// <summary>
    /// アタッチされた Setter のリスト
    /// </summary>
    public IList<Setter> Setters
    {
        get { return (IList<Setter>)this.GetValue(SettersProperty); }
        set { this.SetValue(SettersProperty, value); }
    }

    ~ 中略 ~

    /// <summary>
    /// GestureRecognizer のイベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="args">イベント引数</param>
    private void OnGestured(object sender, EventArgs args)
    {
        // アタッチされた View に Setter を反映
        foreach (var setter in this.Setters)
        {
            this.bindable.SetValue(setter.Property, setter.Value);
        }
    }

BindableProperty に Setters を追加して、GestureRecognizer のイベントハンドラ内で追加されている Setter を View に反映するようにしただけ

お次は XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:b="clr-namespace:XamarinControl.Behaviors;assembly=XamarinControl"
             x:Class="XamarinControl.Views.TopPage">
  <BoxView 
    BackgroundColor="#FFFF8469"
    WidthRequest="200"
    HeightRequest="200"
    HorizontalOptions="Center"
    VerticalOptions="Center">
    <BoxView.Behaviors>
      <b:GestureRecognizeBehavior>
        <b:GestureRecognizeBehavior.GestureRecognizer>
          <TapGestureRecognizer NumberOfTapsRequired="1" />
        </b:GestureRecognizeBehavior.GestureRecognizer>
        <b:GestureRecognizeBehavior.Setters>
          <Setter Property="BoxView.BackgroundColor" Value="#FF84FF69"/>
        </b:GestureRecognizeBehavior.Setters>
      </b:GestureRecognizeBehavior>
    </BoxView.Behaviors>
  </BoxView>
</ContentPage>

BackgroundColor を変更する Setter を追加しました

XAML だけでジェスチャ監視からトリガーアクションの定義まで連携させる記述です

さっそく実行

f:id:matatabi_ux:20150120071110p:plain

タップすると背景色が変わりました

XAML に記述する Setter を変更すればいろいろできそうですね