しっぽを追いかけて

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

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

長押しでイベントが発生するボタンをつくる

需要があるかどうか微妙ですが、一定時間以上長押ししないと発生しないイベントをもつ Button をつくってみました

<ctrl:LongPressableButton Content="長押しボタン" PressTime="3000" LongPressed="LongPressableButton_LongPressed" />

こんな感じで PressTime に長押しする時間(ミリ秒)と LongPressed に長押しされた際に呼び出すイベントハンドラを指定して使うイメージのものです

コードは下記の通りです

/// <summary>
/// 長押し可能なボタン
/// </summary>
public class LongPressableButton : Button
{
    #region Privates

    /// <summary>
    /// 長押しタイマー
    /// </summary>
    private DispatcherTimer timer = new DispatcherTimer();

    /// <summary>
    /// 押下イベントハンドラ
    /// </summary>
    private PointerEventHandler onPointerPressedEventHandler = null;

    /// <summary>
    /// 押上イベントハンドラ
    /// </summary>
    private PointerEventHandler onPointerReleasedEventHandler = null;

    #endregion //Privates

    #region PressTime 依存関係プロパティ
    /// <summary>
    /// 長押し時間 依存関係プロパティ
    /// </summary>
    public static readonly DependencyProperty PressTimeProperty
        = DependencyProperty.Register(
        "PressTime",
        typeof(int),
        typeof(LongPressableButton),
        new PropertyMetadata(
        2000,
        (s, e) =>
        {
            var control = s as LongPressableButton;
            if (control != null)
            {
                control.OnPressTimeChanged();
            }
        }));

    /// <summary>
    /// 長押し時間 変更イベントハンドラ
    /// </summary>
    private void OnPressTimeChanged()
    {
        this.timer.Tick -= this.OnTimeout;
        this.timer.Interval = TimeSpan.FromMilliseconds(this.PressTime);
        this.timer.Tick += this.OnTimeout;
    }

    /// <summary>
    /// 長押し時間
    /// </summary>
    public int PressTime
    {
        get { return (int)this.GetValue(PressTimeProperty); }
        set { this.SetValue(PressTimeProperty, value); }
    }
    #endregion //PressTime 依存関係プロパティ

    /// <summary>
    /// 長押しイベント
    /// </summary>
    public event RoutedEventHandler LongPressed = null;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public LongPressableButton()
    {
        this.Unloaded += this.OnUnloaded;
        this.OnPressTimeChanged();

        this.onPointerPressedEventHandler = new PointerEventHandler(this.OnPointerPressed);
        this.onPointerReleasedEventHandler = new PointerEventHandler(this.OnPointerReleased);

        this.AddHandler(UIElement.PointerPressedEvent, this.onPointerPressedEventHandler, true);
        this.AddHandler(UIElement.PointerReleasedEvent, this.onPointerReleasedEventHandler, true);
    }

    /// <summary>
    /// 破棄イベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnUnloaded(object sender, RoutedEventArgs e)
    {
        this.Unloaded -= this.OnUnloaded;
        this.timer.Tick -= this.OnTimeout;
        this.RemoveHandler(UIElement.PointerPressedEvent, this.onPointerPressedEventHandler);
        this.RemoveHandler(UIElement.PointerReleasedEvent, this.onPointerReleasedEventHandler);
    }

    /// <summary>
    /// 押下イベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
    {
        this.timer.Start();
    }

    /// <summary>
    /// 押上イベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
    {
        this.timer.Stop();
    }

    /// <summary>
    /// タイムアウトイベントハンドラ
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnTimeout(object sender, object e)
    {
        if (this.LongPressed != null)
        {
            this.LongPressed(this, new RoutedEventArgs());
        }
    }
}

そんなに大したことはしてないですが、AddHandler で第三引数 true でハンドラ登録をしているところがポイントです

        this.onPointerPressedEventHandler = new PointerEventHandler(this.OnPointerPressed);
        this.onPointerReleasedEventHandler = new PointerEventHandler(this.OnPointerReleased);

        this.AddHandler(UIElement.PointerPressedEvent, this.onPointerPressedEventHandler, true);
        this.AddHandler(UIElement.PointerReleasedEvent, this.onPointerReleasedEventHandler, true);

継承元の Button 自体が PointerPressedEvent、PointerReleasedEvent のイベントを処理しているので、通常の PointerPressed や PointerReleased のイベントハンドラ登録ではイベントが無視されるのでこうする必要があります

つくっておいてなんですが、利用することはほぼないような・・・;