Pourquoi ne pas ce gestionnaire de classe attaché à un feu d'événement tunnel avant un gestionnaire d'instance?

StackOverflow https://stackoverflow.com/questions/9320916

Question

Selon cet article MSDN (entre autres),

gestionnaires de classe sont appelés avant les gestionnaires d'écoute d'instance sont fixés à une instance de cette classe, chaque fois qu'un événement routé atteint une instance d'élément sur son itinéraire.

Je suis tout à fait nouveau pour RoutedEvents donc il y a une chance que j'ai une erreur dans mon code, mais il semble comme si un gestionnaire de classe attaché à un RoutedEvent qui est déclaré comme RoutingStrategy.Tunnel fait pas toujours le feu avant que les gestionnaires d'instance attachés au même événement.

Dans mon exemple ci-dessous, je l'ai créé une classe de contrôle TouchButton avec un RoutedEvent à effet tunnel et une RoutedEvent bouillonnante. Je gestionnaires de classe enregistré pour chacun. J'ai ensuite créé une instance de la classe dans une fenêtre et une poignée chaque événement dans le derrière de code. I ci le même gestionnaire d'événement à effet tunnel à la fois sur l'élément de classe et le Grid qui le contient. Les quatre gestionnaires affichent leur nom dans une MessageBox afin que vous puissiez voir clairement l'ordre d'exécution.

  1. Grille instance PreviewTouch
  2. Classe TouchButton_PreviewTouch
  3. TouchButton instance PreviewTouch
  4. Classe TouchButton_Touch
  5. TouchButton instance Appuyez sur

Cela signifie que si j'appelle e.Handled = true; dans le gestionnaire d'événements de classe PreviewTouch, je peux arrêter l'exécution d'atteindre tous les autres gestionnaires d'événements à l'exception de celui attaché à l'élément de Grid. Est-ce censé être comme ça, ou ai-je fait une erreur quelque part de? Sinon, comment puis-je arrêter l'exécution d'atteindre tous instance gestionnaire d'événements?

Voici la classe:

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));
    }
}

Voici les gestionnaires d'instance dans le code de la fenêtre derrière:

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));
}

Voici le XAML de commande:

<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>

Je ne comprends que l'événement de tunnel est gérée par l'élément Grid avant « tunnel » jusqu'à l'élément TouchButton, mais je pense que les gestionnaires de classe étaient toujours censés feu avant que les gestionnaires d'instance. Sinon, comment puis-je y parvenir?

MISE À JOUR >>>

Merci à la réponse de @ optimiste, je réussi à trouver un moyen d'arrêter toutes les instances gestionnaires de gestion de l'événement. Si au lieu de remplacer le type de manutention classe déclarée de TouchButton avec Grid comme suggéré optimiste, je le remplace par FrameworkElement, il va attraper tous les contrôles dérivés FrameworkElement.

EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent, 
new RoutedEventHandler(TouchButton_PreviewTouch), true);
Était-ce utile?

La solution

des moyens d'article MSDN - Lorsqu'un événement de déplacement trouve un élément (dans l'arbre) qui présente à la fois la fourniture de gestionnaire de classe et l'instance puis il invoque gestionnaire de classe avant le gestionnaire d'instance. Par conséquent, dans ce cas, lorsque l'événement est tiré et tunneling de l'extérieur vers, il rencontre la grille, mais la classe Grille ne pas gestionnaire de classe il appelle simplement le gestionnaire d'instance utilisée par l'instance « Grid ». Si cette ligne est ajoutée bouton à bascule -

EventManager.RegisterClassHandler (typeof ( Grille ), PreviewTouchEvent, nouveau RoutedEventHandler (TouchButton_PreviewTouch), true);

puis avant le gestionnaire d'instance de grille, le gestionnaire de classe correspondante sera appelée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top