Perché il pulsante fa clic su "Bubble up Visual Tree" su StackPanel come afferma l'articolo di MSDN?

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

  •  20-08-2019
  •  | 
  •  

Domanda

Nell'articolo MSDN Comprensione di eventi e comandi instradati in WPF, afferma

Un evento bolle (propagare) l'albero visivo dall'elemento sorgente fino a quando non è stato gestito o raggiunge l'elemento radice.

Tuttavia, in questo esempio, quando si fa clic sul pulsante, Non "bolle l'albero visivo" per essere gestito dall'evento Parent Stackpanel, cioè fare clic sul pulsante non fa alcun evento.

Perché no? Cosa significano allora "gorgogliando" se non questo?

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>

Code-behind:

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

    }
}
È stato utile?

Soluzione

L'evento bolle, fino a quando non viene gestito ...

Poiché il pulsante fa qualcosa con i clic del mouse, assorbe il tuo evento del mouse e lo trasforma in un clickevent.

Se si utilizza AntepryMouseDown, vedi che StackPanel riceve prima l'evento prima del pulsante. Eventi di anteprima Utilizzare l'approccio tunnel down ..

Altri suggerimenti

Come altri hanno detto, è perché il MouseDown L'evento viene gestito dal Button prima che possa essere ulteriormente gorgogliato. Puoi vederlo in Reflector, in ButtonBase.OnMouseLeftButtonDown:

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

Una soluzione è ascoltare un MouseDown evento e indica che non ti interessa se l'evento viene gestito. Puoi farlo con il AddHandler metodo. Ha un sovraccarico booleano che ti consente di ascoltare eventi già gestiti.

Se lo fai da qualche parte invece di impostare il gestore di mouse in XAML:

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

Riceverai tutto MouseDown eventi su TheStackPanel, indipendentemente dal fatto che siano stati gestiti.

Inoltre, se si desidera che lo stackpanel riceva l'evento, modifica Stackpanel XAML in:

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

e la firma dell'evento a:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

In questo caso, StackPanel riceverà l'evento di clic del pulsante. Tuttavia, facendo clic sullo stackpanel stesso non farà scattare alcun evento, poiché ascolta specificamente un clic del pulsante.

È perché tutti i messaggi vengono catturati gestito per pulsante e messaggi fermati Il messaggio si interrompe gorgogliare lì. La risposta è giusta nel testo della tua domanda:

Un evento bolle (propagare) l'albero visivo dall'elemento sorgente Fino a quando non è stato gestito o raggiunge l'elemento radice.

MODIFICARE:

Edward Tanguay (OP) ha commentato questa risposta e sto copiando il suo commento qui perché è molto rilevante:

"Non vedo che il pulsante stia gestendo l'evento, cioè non ho un gestore di clic sul pulsante, ho un gestore di clic (mouseown) sullo stackpanel e quindi penso che salverebbe oltre il pulsante da quando il Il pulsante non lo gestisce e viene gestito dallo stackpanel che fa, giusto? "

Hai ragione. Il pulsante non gestisce l'evento del mouse perché nessun gestore è stato specificato per questo controllo.

Ma, quindi, Mousedown è in qualche modo particolare. Almeno nei moduli di Windows viene utilizzato per avviare azioni come disegno e trascinamento, quando un controllo ottiene l'evento, procede a intrappolare tutti i successivi messaggi del mouse anche se non hai definito gestori per esso. Questa trappola viene eseguita quando il controllo imposta la proprietà di cattura su True e questo impedisce effettivamente gli eventi successivi di essere gorgogliato. La proprietà di acquisizione viene restituita su False dai moduli Windows quando si ottiene un evento del mouse.

Ripeto, questo è il modo in cui funziona nelle forme di Windows, potresti voler ricontrollare questo, ma, IMHO non c'è motivo per cui questo dovrebbe essere diverso per WPF.

Per riferimento: SE la sezione "Elaborazione dei moduli Windows" a http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (Scorri leggermente verso il basso dal centro della pagina).

Nota: consultare il mio commento alla risposta di Arcturu per un riferimento sugli eventi a bolle e tunneling solleva sequenze.

Pulsante Evento Soppressione il mouseo e il mouse perché l'evento pulsante è un evento di alto livello e hanno un bit di codice che danno la maniglia flag vero questa causa soppressa per il mousdown per risolvere questo problema è possibile aggiungere questo codice nel costruttore della finestra

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top