wpf - control - ¿Por qué no se hace clic en el evento del botón "burbuja de árbol visual" en StackPanel como dice el artículo de MSDN?
wpf controls (5)
En el artículo de MSDN Descripción de los comandos y eventos enrutados en WPF , se indica
un evento formará una burbuja (se propagará) hacia arriba 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 StackPanel principal , es decir, al hacer clic en el botón no se activa ningún evento.
Por qué no? ¿Qué quieren decir con "burbujear" si no 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.";
}
}
}
Además, si desea que el panel de la pila reciba el evento, cambie el panel de pila 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 panel de la pila recibirá el evento de clic del botón. Sin embargo, hacer clic en el panel de la pila no activará ningún evento, ya que escucha específicamente el clic de un botón.
Como otros lo han dicho, es porque el evento MouseDown
es manejado por el Button
antes de que se pueda seguir burbujeando. 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 evento MouseDown
e indicar que no le importa si el evento se maneja. Puedes hacer esto con el método AddHandler
. Tiene una sobrecarga booleana que te 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á todos los eventos de MouseDown
en TheStackPanel
, independientemente de si se han manejado.
El evento burbujea, hasta que se maneja ...
Como el botón hace algo con los clics del mouse, absorbe el evento del mouse y lo convierte en un evento de clic.
Si usa PreviewMouseDown, verá que StackPanel recibe primero el evento antes de que lo haga el botón. Los eventos de vista previa utilizan el enfoque de túnel hacia abajo.
Esto se debe a que todos los mensajes se están capturando manejados por el botón y los mensajes se detienen, el mensaje deja de burbujear allí. La respuesta está justo en el texto de tu pregunta:
Un evento formará una burbuja (propagará) hacia arriba en el árbol visual desde el elemento fuente hasta que se haya manejado o llegue al elemento raíz.
EDITAR:
Edward Tanguay (OP) comentó esta respuesta y estoy copiando su comentario aquí porque es muy relevante:
"No veo que el botón ESTÁ manejando el evento, es decir, no tengo un controlador de clics en el botón, SÍ tengo un controlador de clics (MouseDown) en el Panel de Pilates y, por lo tanto, creo que desbordaría el botón PAST desde el botón el botón no lo maneja y se maneja con el panel de la pila, lo que hace, ¿verdad? "
Tienes razón. Button no controla 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 que, cuando un control obtiene el evento, continúa atrapando todos los mensajes del mouse subsiguientes, incluso si no ha definido controladores para él. Esta trampa se realiza cuando el control establece la propiedad Captura en Verdadero y esto efectivamente detiene la propagación de eventos subsiguientes. La propiedad de captura se establece de nuevo en Falso por Windows Forms cuando recibe un evento MouseUp.
Repito, esta es la forma en que funciona en los formularios Windows Forms, es posible que desee volver a verificar esto, pero en mi humilde opinión no hay ninguna razón por la que esto debería ser diferente para WPF.
Para referencia: vea la sección "Procesamiento de formularios Windows Forms" en http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (desplácese ligeramente hacia abajo desde el centro de la página).
Nota: Consulte mi comentario a la respuesta de Arcturu para obtener una referencia sobre las burbujas y los eventos de tunelización provocan secuencias.
evento de botón Suprimir la tecla del ratón y el mouseup porque el evento del botón es un evento de alto nivel y tiene un poco de código que le da un verdadero control a la bandera esta causa Suprimido por la tecla del ratón para resolver este problema, puede agregar este código en el constructor de la ventana
TheButton.AddHandler(
UIElement.MouseDownEvent,
new MouseButtonEventHandler(TheStackPanel_MouseDown),
true);