¿Por qué este manejador de clase no se adjunta a un incendio en el evento de túneles antes de un manejador de instancias?

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

Pregunta

De acuerdo a Este artículo de MSDN (entre otros),

Los manejadores de clase se invocan antes de los manejadores de oyentes de instancia que están conectados a una instancia de esa clase, cada vez que un evento enrutado alcanza una instancia de elemento en su ruta.

Soy bastante nuevo en RoutedEventS Entonces existe la posibilidad de que tenga un error en mi código, pero parece que un manejador de clase adjunto a un RoutedEvent que se declara como RoutingStrategy.Tunnel lo hace no Siempre dispare antes de los manejadores de instancia adjuntos al mismo evento.

En mi ejemplo a continuación, he creado un TouchButton clase de control con un túnel RoutedEvent y un burbujeo RoutedEvent. Tengo manejadores de clase registrados para cada uno. Luego creé una instancia de la clase en una ventana y maneje cada evento en el código detrás. Adjunté el mismo manejador para el evento de túneles tanto en el elemento de clase como en el Grid que lo contiene. Los cuatro manejadores muestran su nombre en un MessageBox Entonces puede ver claramente el orden de ejecución.

  1. Instancia de cuadrícula PreviewTouch
  2. Clase TouchButton_PreviewTouch
  3. TouchButton instancia previa vista
  4. Clase TouchButton_Touch
  5. Touch button instancia touch

Esto significa que si llamo e.Handled = true; en la clase PreviewTouch Manitulador de eventos, puedo evitar que la ejecución llegue a todos los demás manejadores de eventos, excepto el adjunto al Grid elemento. ¿Se supone que esto es así, o he cometido un error en alguna parte? De lo contrario, ¿cómo puedo evitar que la ejecución llegue cada Handler de eventos de instancia?

Aquí está la clase:

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

Aquí están los manejadores de instancia en el código de la ventana detrás:

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

Aquí está el control 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>

Entiendo que el evento de túneles es manejado por el Grid elemento antes de 'túneles' hasta el TouchButton Elemento, pero pensé que los manejadores de la clase siempre debían disparar antes de los manejadores de instancia. Si no, ¿cómo puedo lograr esto?

Actualización >>>

Gracias a la respuesta de @sanguine, logré encontrar una manera de evitar que todos los manejadores de instancias manejen el evento. Si en lugar de reemplazar el tipo de manejo de clase declarado de TouchButton con Grid Como suguine sugirió, lo reemplazo con FrameworkElement, entonces atrapará todo FrameworkElement-Controles derivados.

EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent, 
new RoutedEventHandler(TouchButton_PreviewTouch), true);
¿Fue útil?

Solución

El artículo de MSDN significa: cuando un evento de recorrido encuentra un elemento (en el árbol) que tiene la provisión del controlador de clase y de instancias, invoca el controlador de clase antes del controlador de instancias. Por lo tanto, en este caso, cuando el evento se dispara y se tune de fuera a adentro, encuentra la cuadrícula, pero la clase de la cuadrícula no tiene ningún controlador de clase, por lo que simplemente llama al controlador de instancias utilizado por la instancia de "cuadrícula". Si esta línea se agrega en el botón de alternar-

EventManager.RegisterClassHandler (typeof (Cuadrícula), PreviewTouchEvent, New RoutedEventHandler (touchButton_PreviewTouch), true);

Luego, antes del controlador de instancias de Grid, se llamará al controlador de clase correspondiente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top