2009-03-19 11 views
20

En el artículo de MSDN Understanding Routed Events and Commands In WPF, se establece¿Por qué el botón no hace clic en evento "burbujear árbol visual" a StackPanel como estados de artículo de MSDN?

un evento de burbujas (propagar) hasta el árbol visual desde el elemento de origen hasta que se ha manejado o hasta que alcance el elemento raíz.

Sin embargo, en este ejemplo, al hacer clic en el botón, no "burbuja hasta el árbol visual" para conseguir manejado por el padre StackPanel caso, es decir, al hacer clic en los botones incendios ningún caso.

¿Por qué no? ¿Qué significan entonces "burbujeando" si no es esto?

XAML:

<Window x:Class="TestClickEvents456.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel x:Name="TheStackPanel" 
       Background="Yellow" 
       MouseDown="TheStackPanel_MouseDown"> 
     <Button x:Name="TheButton" 
       Margin="10" 
       Content="Click This"/> 
     <TextBlock x:Name="TheMessage" 
        Text="Click the button or the yellow area"/> 
    </StackPanel> 
</Window> 

de código subyacente:

using System.Windows; 
using System.Windows.Input; 

namespace TestClickEvents456 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 

     private void TheStackPanel_MouseDown(object sender, MouseButtonEventArgs e) 
     { 
      TheMessage.Text = "StackPanel was clicked."; 
     } 

    } 
} 

Respuesta

22

El evento se propaga hacia arriba, hasta que se maneja ...

Puesto que el botón hace algo con el mouse hace clic, absorbe el evento del mouse y lo convierte en un evento ClickEvent.

Si utiliza el PreviewMouseDown, verá que la primera StackPanel recibe el evento antes de que el botón de vista previa hace .. eventos utilizan el enfoque del túnel abajo ..

+1

¿Qué hace el botón con el clic de mi mouse? No tengo ningún atributo de clic en el elemento, no estoy manejando el evento click en el código subyacente, entonces, ¿cómo podemos decir que el botón está haciendo algo con los clics del mouse? –

+0

PreviewMouseDown funcionó, gracias. –

+2

Es cierto, pero la implementación predeterminada del botón es absorber el evento del mouse para convertirlo en un evento de clic ... incluso si no hace nada con el clic ... – Arcturus

1

Se debe a que todos los mensajes están siendo capturados manejado mediante el botón y los mensajes detienen el mensaje deja burbujeando allí. La respuesta está en el texto de su pregunta:

Un evento de burbujas (propagar) hasta el árbol visual del elemento de origen hasta que se ha manejado o hasta que alcance el elemento raíz.

EDIT:

Edward Tanguay (OP) ha comentado esta respuesta y estoy copiando su comentario aquí porque es muy relevante:

"No veo que el botón se manejar el evento, es decir, no tengo ningún controlador de clic en el botón, TENGO un controlador de clic (MouseDown) en el StackPanel y, por lo tanto, creo que se moverá el botón PASADO ya que el botón no lo maneja y se maneja el stackpanel que hace, ¿verdad? "

Tienes razón. El botón no está manejando el evento MouseDown porque no se ha especificado ningún controlador para ese control.

Pero, entonces, MouseDown es particular de alguna manera. Al menos en Windows Forms se usa para iniciar acciones como dibujar y arrastrar, por lo tanto, cuando un control obtiene el evento, procede a atrapar todos los mensajes de mouse subsiguientes, incluso si no ha definido manejadores para él.Esta trampa se realiza cuando el control establece la propiedad de Captura en Verdadero y esto efectivamente evita que los eventos subsecuentes se borren. La propiedad de captura se establece en False por Windows Forms cuando se produce un evento MouseUp.

Repito, esta es la forma en que funciona en Windows Forms, es posible que desee comprobar esto pero, en mi humilde opinión, no hay ninguna razón por la que esto debería ser diferente para WPF.

Para referencia: Se la sección "Procesamiento de Windows Forms" en http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (desplácese un poco hacia abajo desde el centro de la página).

Nota: Vea mi comentario a la respuesta de Arcturu para una referencia sobre eventos de burbujas y túneles que elevan secuencias.

+0

No veo que el botón ES maneje el evento, es decirNo tengo ningún manejador de clics en el botón, SÍ tengo un manejador de clics (MouseDown) en el StackPanel y, por lo tanto, creo que aparecería en el botón PASAR, ya que el botón no lo maneja y el panel de distribución lo maneja, ¿derecho? –

+0

Tienes razón. Edité mi respuesta. – vmarquez

7

Además, si desea que el StackPanel para recibir el evento, cambiar el xaml StackPanel a:

<StackPanel x:Name="TheStackPanel" 
      Background="Yellow" 
      Button.Click="TheStackPanel_MouseDown" /> 

y la firma de eventos para:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e) 

En este caso, el StackPanel se recibir el evento de clic del botón. Sin embargo, al hacer clic en el panel de pila no se desencadenará ningún evento, ya que escucha específicamente un clic del botón.

+0

hmm, he visto el botón.Haga clic en los artículos también, pero mi StackPanel no tiene ese atributo (?), El único atributo similar que obtengo en intellisense es "ButtonBase.Click" que me da "No overload for" TheStackPanel_MouseDown 'coincide con delegar' System.Windows.RoutedEventHandler '", ¿por qué? –

+0

Hmmm, me funciona con ButtonBase.Click y Button.Haga clic en el XAML (creo que Button.Click simplemente no se muestra en intellisense, pero debería funcionar) y con la firma del evento especificado. ¿Has cambiado MouseButtonEventArgs a RoutedEventArgs? – Razzie

8

Como han dicho otros, es porque el evento MouseDown es manejado por el Button antes de que pueda seguir burbujeando. Esto se puede ver en el reflector, en ButtonBase.OnMouseLeftButtonDown:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) 
{ 
    if (this.ClickMode != ClickMode.Hover) 
    { 
     e.Handled = true; 
     // SNIP... 
    } 
    base.OnMouseLeftButtonDown(e); 
} 

Una solución es escuchar para un evento MouseDown, e indicar que no le importa si se maneja el evento. Puede hacerlo con el método AddHandler. Tiene una sobrecarga booleana que le permite escuchar eventos que ya están manejados.

Si hace esto en algún lugar de establecer el manejador MouseDown en XAML:

TheStackPanel.AddHandler(MouseDownEvent, new MouseButtonEventHandler(TheStackPanel_MouseDown), true); 

que recibirá todos los eventos en MouseDownTheStackPanel, independientemente de si han sido manipulados.

+0

¿Qué es "MouseDownEvent"? RoutedEvent es una clase sellada, por lo que algunos objetos deben llevar instancias de esos? – flq

+0

Ah, encontré algo. 'Mouse.AddXXX (DependencyObject, EventHandler);' – flq

2

evento de botón Suprimir la mousedown y mouseup debido evento de botón es el evento de alto nivel y tienen algo de código que dar a bandera manejar cierto esta causa suprimida por mousdown para resolver este problema, puede agregar este código en el constructor de la ventana

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown), 
    true); 
Cuestiones relacionadas