22

MSDN の記事Understanding Routed Events and Commands In WPFでは、次のように述べています。

イベントは、処理されるかルート要素に到達するまで、ソース要素からビジュアル ツリーをバブル (伝播) します。

ただし、この例では、ボタンをクリックしても、親の StackPanel イベントによって処理されるように「ビジュアル ツリーをバブルアップ」しません。つまり、ボタンをクリックしてもイベントは発生しません。

なぜだめですか?そうでない場合、「泡立つ」とはどういう意味ですか?

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>

コード ビハインド:

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

    }
}
4

5 に答える 5

25

イベントは、処理されるまで泡立ちます...

Button はマウス クリックで何かを行うため、マウス イベントを吸収して ClickEvent に変換します。

PreviewMouseDown を使用すると、ボタンが受信する前に、StackPanel が最初にイベントを受信することがわかります。プレビュー イベントは、Tunnel down アプローチを使用します。

于 2009-03-19T13:54:19.927 に答える
8

他の人が言っているように、それはイベントがさらにバブルされる前にMouseDownイベントが処理されるためです。Buttonこれは、Reflectorの次の場所で確認できますButtonBase.OnMouseLeftButtonDown

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

1つの解決策は、イベントをリッスンし、MouseDownイベントが処理されるかどうかを気にしないことを示すことです。このメソッドを使用してこれを行うことができますAddHandler。すでに処理されているイベントをリッスンできるブールオーバーロードがあります。

XAMLでMouseDownハンドラーを設定する代わりに、これをどこかで行う場合:

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

MouseDown処理されたかどうかに関係なく、ですべてのイベントを受け取りますTheStackPanel

于 2009-03-19T18:41:14.020 に答える
7

さらに、stackpanel がイベントを受け取るようにする場合は、stackpanel xaml を次のように変更します。

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

およびイベントの署名は次のとおりです。

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

この場合、stackpanel はボタンのクリック イベントを受け取ります。ただし、stackpanel 自体をクリックしてもイベントは発生しません。これは、特にボタンのクリックをリッスンするためです。

于 2009-03-19T14:00:18.727 に答える
2

これは、すべてのメッセージがキャプチャされて Button によって処理され、メッセージがそこでバブルを停止するためです。答えはあなたの質問のテキストにあります:

イベントは、処理されるかルート要素に到達するまで、ソース要素からビジュアル ツリーをバブル (伝播) します。

編集:

Edward Tanguay (OP) がこの回答にコメントしました。関連性が非常に高いため、ここに彼のコメントをコピーします。

「ボタンがイベントを処理していることがわかりません。つまり、ボタンにクリック ハンドラーがありません。StackPanel にクリック ハンドラー (MouseDown) があるため、ボタンを過ぎてバブルアップすると思います。ボタンはそれを処理せず、スタックパネルによって処理されますよね?」

あなたが正しいです。そのコントロールでハンドラーが指定されていないため、ボタンは MouseDown イベントを処理していません。

しかし、MouseDown はある意味で特殊です。少なくとも Windows フォームでは、描画やドラッグなどのアクションを開始するために使用されるため、コントロールがイベントを取得すると、ハンドラーを定義していなくても、後続のすべてのマウス メッセージをトラップします。このトラップは、コントロールが Capture プロパティを True に設定したときに実行され、これにより後続のイベントがバブルアップされるのを効果的に停止します。Capture プロパティは、MouseUp イベントを取得すると、Windows フォームによって False に戻されます。

繰り返しますが、これは Windows フォームでの動作です。これを再確認することをお勧めしますが、WPF でこれが異なる理由はありません。

参考: http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspxの「Windows フォーム処理」セクションを参照してください (ページの中央から少し下にスクロールします)。

注: バブルおよびトンネリング イベントの発生シーケンスに関するリファレンスについては、Arcturu の回答に対する私のコメントを参照してください。

于 2009-03-19T13:56:40.170 に答える
2

ボタンイベントは高レベルのイベントであり、フラグハンドルをtrueにするコードが少しあるため、マウスダウンとマウスアップを抑制します。これにより、マウスダウンが抑制されてこの問題が解決され、ウィンドウのコンストラクターにこのコードを追加できます

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
于 2013-01-16T20:02:18.127 に答える