1

このMSDNの記事(とりわけ)によると、

クラスハンドラーは、ルーティングされたイベントがそのルート内の要素インスタンスに到達するたびに、そのクラスのインスタンスにアタッチされているインスタンスリスナーハンドラーの前に呼び出されます。

私はRoutedEventsにまったく慣れていないので、コードに間違いがある可能性がありますが、RoutedEventとして宣言されたにアタッチされたクラスハンドラーは、同じイベントにアタッチされたインスタンスハンドラーの前に常に起動するとは限らないRoutingStrategy.Tunnelようです。

TouchButton以下の例では、トンネリングRoutedEventとバブリングを使用してコントロールクラスを作成しましたRoutedEvent。それぞれにクラスハンドラーを登録しました。次に、ウィンドウにクラスのインスタンスを作成し、コードビハインドで各イベントを処理します。クラス要素とそれを含むの両方で、トンネリングイベントに同じハンドラーをアタッチしましたGrid。4つのハンドラーすべてに名前が表示さMessageBoxれるため、実行の順序を明確に確認できます。

  1. グリッドインスタンスPreviewTouch
  2. クラスTouchButton_PreviewTouch
  3. TouchButtonインスタンスPreviewTouch
  4. クラスTouchButton_Touch
  5. タッチボタンインスタンスタッチ

これはe.Handled = true;、クラスPreviewTouchイベントハンドラーを呼び出すと、要素にアタッチされているものを除いて、実行が他のすべてのイベントハンドラーに到達するのを停止できることを意味しGridます。これはこんな感じなのか、どこかで間違えたのか?それ以外の場合、実行がすべてのインスタンスイベントハンドラーに到達するのを停止するにはどうすればよいですか?

クラスは次のとおりです。

public class TouchButton : Button
{
    static TouchButton()
    {
        EventManager.RegisterClassHandler(typeof(TouchButton), PreviewTouchEvent, 
new RoutedEventHandler(TouchButton_PreviewTouch), true);
        EventManager.RegisterClassHandler(typeof(TouchButton), TouchEvent, 
new RoutedEventHandler(TouchButton_Touch), true);
    }

    private static void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Class TouchButton_PreviewTouch");
    }

    private static void TouchButton_Touch(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Class TouchButton_Touch");
    }

    public static RoutedEvent TouchEvent = EventManager.RegisterRoutedEvent("Touch", 
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TouchButton));

    public event RoutedEventHandler Touch
    {
        add { AddHandler(TouchEvent, value); }
        remove { RemoveHandler(TouchEvent, value); }
    }

    public static RoutedEvent PreviewTouchEvent = EventManager.RegisterRoutedEvent(
"PreviewTouch", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), 
typeof(TouchButton));

    public event RoutedEventHandler PreviewTouch
    {
        add { AddHandler(PreviewTouchEvent, value); }
        remove { RemoveHandler(PreviewTouchEvent, value); }
    }

    protected override void OnClick()
    {
        RaiseTouchEvent();
    }

    private void RaiseTouchEvent()
    {
        RoutedEventArgs touchEventArgs = new RoutedEventArgs(PreviewTouchEvent);
        RaiseEvent(touchEventArgs);
        if (!touchEventArgs.Handled) RaiseEvent(new RoutedEventArgs(TouchEvent));
    }
}

背後にあるウィンドウコードのインスタンスハンドラは次のとおりです。

private void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
{
    MessageBox.Show(string.Format("{0} Instance PreviewTouch", 
((FrameworkElement)sender).Name));
}

private void TouchButton_Touch(object sender, RoutedEventArgs e)
{
    MessageBox.Show(string.Format("{0} Instance Touch", 
((FrameworkElement)sender).Name));
}

コントロールXAMLは次のとおりです。

<Grid Name="Grid" Controls:TouchButton.PreviewTouch="TouchButton_PreviewTouch">
    <Controls:TouchButton x:Name="TouchButton" Width="200" Height="45" FontSize="24" 
Content="Touch me" Touch="TouchButton_Touch" PreviewTouch="TouchButton_PreviewTouch" />
</Grid>

トンネリングイベントは、Grid要素に「トンネリング」する前に要素によって処理されることを理解してTouchButtonいますが、クラスハンドラーは常にインスタンスハンドラーの前に起動することになっていると思いました。そうでない場合、どうすればこれを達成できますか?

更新>>>

@sanguineの回答のおかげで、すべてのインスタンスハンドラーがイベントを処理しないようにする方法を見つけることができました。宣言されたクラス処理タイプをTouchButtonsanguineGridが提案したように置き換える代わりに、に置き換えると、すべての派生コントロールFrameworkElementをキャッチします。FrameworkElement

EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent, 
new RoutedEventHandler(TouchButton_PreviewTouch), true);
4

1 に答える 1

0

MSDN 記事の意味 - トラバース イベントがクラスとインスタンス ハンドラーの両方を提供する要素 (ツリー内) を検出すると、インスタンス ハンドラーの前にクラス ハンドラーを呼び出します。したがって、この場合、イベントが発生し、アウトからインにトンネリングされると、グリッドに遭遇しますが、Grid クラスにはクラス ハンドラーがないため、「Grid」インスタンスによって使用されるインスタンス ハンドラーを呼び出すだけです。この行がトグルボタンに追加された場合 -

EventManager.RegisterClassHandler(typeof( Grid ), PreviewTouchEvent, new RoutedEventHandler(TouchButton_PreviewTouch), true);

次に、Grid のインスタンス ハンドラーの前に、対応するクラス ハンドラーが呼び出されます。

于 2012-02-17T10:44:50.063 に答える