¿Por qué no hace clic en Button el evento "Bubble Up Visual Tree" a Stackpanel como dice el artículo de MSDN?

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

  •  20-08-2019
  •  | 
  •  

Pregunta

En el artículo de MSDN Comprender eventos y comandos enrutados en WPF, afirma

Un evento burbujeará (propague) en el árbol visual desde el elemento fuente hasta que se haya manejado o llegue al elemento raíz.

Sin embargo, en este ejemplo, cuando hace clic en el botón, No "burbujea el árbol visual" para ser manejado por el evento de los padres Stackpanel, es decir, haciendo clic en el botón No dispara ningún evento.

¿Por que no? ¿Qué quieren decir 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>

código detrás:

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.";
        }

    }
}
¿Fue útil?

Solución

El evento burbujea, hasta que se maneja ...

Dado que el botón hace algo con los clics del mouse, absorbe el evento de su mouse y lo convierte en un clickevent.

Si usa PreviewMouseDown, ve que el StackPanel primero recibe el evento antes de que lo haga el botón. Los eventos de vista previa usan el enfoque de túnel hacia abajo.

Otros consejos

Como otros han dicho, es porque el MouseDown El evento es manejado por el Button antes de que pueda burbujear más. Puedes ver esto en 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 un MouseDown evento, e indique que no le importa si el evento se maneja. Puedes hacer esto con el AddHandler método. Tiene una sobrecarga booleana que le permite escuchar eventos que ya están manejados.

Si haces esto en algún lugar en lugar de configurar el controlador Mousedown en XAML:

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

Recibirás todo MouseDown eventos en TheStackPanel, independientemente de si han sido manejados.

Además, si desea que el StackPanel reciba el evento, cambie el StackPanel XAML a:

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

y la firma del evento a:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

En este caso, el StackPanel recibirá el evento de clic del botón. Sin embargo, hacer clic en el stackpanel en sí no disparará ningún evento, ya que escucha específicamente a un clic de botón.

Es porque todos los mensajes están siendo capturados manejado por botón y mensajes se detiene El mensaje se detiene burbujeando allí. La respuesta es correcta en el texto de su pregunta:

Un evento burbujee (propague) en el árbol visual desde el elemento fuente Hasta que se haya manejado o llega al elemento raíz.

EDITAR:

Edward Tanguay (OP) comentó sobre esta respuesta y estoy copiando su comentario aquí porque es muy relevante:

"No veo que el botón maneje el evento, es decir, no tengo controlador de clics en el botón, tengo un controlador de clic (MouseDown) en el StackPanel y, por lo tanto, creo que pasaría más allá del botón desde el botón desde el botón El botón no lo maneja y es manejado por el Stackpanel que lo hace, ¿verdad? "

Tienes razón. El botón no maneja el evento MouseDown porque no se ha especificado ningún controlador para ello en ese control.

Pero, entonces, Mousedown es particular de alguna manera. Al menos en los formularios de Windows se utiliza para iniciar acciones como dibujar y arrastrar, por lo que cuando un control obtiene el evento, procede a atrapar todos los mensajes posteriores del mouse, incluso si no ha definido los manejadores para ello. Esta trampa se realiza cuando el control establece la propiedad de captura en verdadero y esto impide que los eventos posteriores se burbujeen. La propiedad de captura está retrocedida en False por los formularios de Windows cuando obtiene un evento de mouseup.

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

Como referencia: SE la sección "Procesamiento de formularios de Windows" en http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (Desplácese ligeramente hacia abajo desde el medio de la página).

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

Evento de botón Suprimir el mouseDown y el mouseup porque el evento de botones es un evento de alto nivel y tiene un poco de código que le da a la manejo de la bandera verdadera esta causa suprimida para que Mousdown resuelva este problema, puede agregar este código en el constructor de la ventana

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top