8

私はWPFで比較的新しいです。MouseDownEvent と PreviewMouseDownEvent の違いを理解しようとしています。

私は WPF イベント戦略を理解し、MouseDown イベントがバブリング イベントであり、PreviewMouseDown がトンネリング イベントであることを理解しています。

この MSDN の概要http://msdn.microsoft.com/en-us/library/ms742806.aspx#routingによると、これらのイベントが発生する順序も理解しています(そこに例のある図があります)。

だから私は自分自身をコーディングしようとしました、例えばこれをチェックしてください:

<Grid x:Name="grid" Width="250">
    <StackPanel Mouse.MouseDown="StackPanel_MouseDown" PreviewMouseDown="StackPanel_PreviewMouseDown">
    <WPFVisualizerExample:MyButton x:Name="B1" PreviewMouseDown="B1_PreviewMouseDown" MouseDown="B1_MouseDown" Margin="5,5,5,5">
            <WPFVisualizerExample:MyButton x:Name="B2" PreviewMouseDown="B2_PreviewMouseDown" MouseDown="B2_MouseDown"  Margin="5,5,5,5">
                <WPFVisualizerExample:MyButton x:Name="B3" PreviewMouseDown="B3_PreviewMouseDown" MouseDown="B3_MouseDown"  Margin="5,5,5,5">Click Me</WPFVisualizerExample:MyButton>
            </WPFVisualizerExample:MyButton>
    </WPFVisualizerExample:MyButton>           
    </StackPanel>        
</Grid>

各イベント (プレビューと非プレビュー) のイベント ハンドラーがあり、何が起こっているか、どのイベントがスローされているかを確認したかった (イベントごとにメッセージ ボックスが表示されている)。

「MyButton」ユーザー コントロールは、単純にベース ボタンを拡張し、OnMouseDown と OnPreviewMouseDown をオーバーライドして、e.Handled を false に設定します。

    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnMouseDown(e);
        e.Handled = false;
    }

    protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnPreviewMouseDown(e);
        e.Handled = false;
    }

(これとこれなしで試しました)。

MSDN の概要 (上記のリンク) によると、3 つの要素がある場合、イベント ルートは次のようになります。

ルート要素の PreviewMouseDown (トンネル)。

中間要素 #1 の PreviewMouseDown (トンネル)。

ソース要素 #2 の PreviewMouseDown (トンネル)。

ソース要素 #2 の MouseDown (吹き出し)。

中間要素 #1 の MouseDown (吹き出し)。

ルート要素の MouseDown (バブル)。

したがって、上記に従ってメッセージボックスが表示されることを期待していました。なんらかの理由から-プレビューイベントのみがスローされていることを理解していません(MSDNの言うことによると Preview_B1=>Preview_B2=>Preview_B3 )。私の予想は、Preview_B1=>Preview_B2=>Preview_B3=>NonPreview_B3=>NonPreview_B2=>NonPreview_B1 でした。

ただし、プレビュー以外のイベントはまったくスローされていません。

したがって、基本的に私はイベントのルートを理解していません.MSDNの概要から、ルートはルート要素から始まり、ソース要素に下り(トンネル)、ルート要素に戻る(バブル)ことを理解しましたが、これは実際に起こっていることではありません。

このイベントがどのように機能しているかを理解することは、私にとって非常に重要です。ここで基本的なことを理解していない可能性があります。助けていただければ幸いです。

ありがとう!! -ギリ

4

4 に答える 4

7

Button コントロールの機能は Click イベントを生成する (または Command を起動する) ことであるため、Mouse イベントの扱いは他のコントロールとは少し異なります。Button が PreviewMouseDown イベントを受け取ると、それを Click イベントに変換し、Preview のそれ以上のトンネリングと MouseDown バブリング イベントをキャンセルします。これには、Button の ClickMode 設定に応じて、いくつかのバリエーションがあります。Mouse イベント自体を使用したい場合は、代わりに ContentControl を使用できます (実際に試してみると、期待どおりの結果が得られるはずです) が、ほとんどの場合、Button.Click を使用する方がはるかに簡単であることがわかるでしょう。

アップデート

イベント ルーティングが停止する原因となっている何かがコード内で発生している必要があります。これは、予想される出力を示すことを確認したあなたの例に似ています(要素を明確にするためにいくつかのスタイルが追加されています):

<Window.Resources>
    <Style TargetType="{x:Type ContentControl}">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="Background" Value="PaleGreen" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<StackPanel Tag="Panel" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
    <ContentControl BorderBrush="Red" Tag="C1" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
        <ContentControl BorderBrush="Green" Tag="C2" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
            <ContentControl Content="Click Me" BorderBrush="Blue" Tag="C3" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown"/>
        </ContentControl>
    </ContentControl>
</StackPanel>

デバッグに書き込む単純なハンドラー:

private void PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Preview");
}

private void MouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Bubble");
}

デバッグ出力 (中央のテキストがクリックされた場合) は次のとおりです。

パネル プレビュー
C1 プレビュー
C2 プレビュー
C3 プレビュー
C3 バブル
C2 バブル
C1 バブル
パネル バブル

于 2010-06-05T22:27:02.300 に答える
2

私は最近、ルーティング イベントの概念を研究しています。私のテスト アプリケーションでは、主な違いはMessageBox.Show()メソッドの乱用です。イベントが発生していることを通知するために使用すると、最初にすべてのトンネリングPreviewMouseDownイベントが発生し、適切なメッセージ ボックスが表示され、フォーカスがアボートされるか、バブリングMouseDownイベントが処理されるようです。与えられたコード例では、通知の方法を変更できます (たとえばDebug.WriteLine、ジョンの例のように、またはいくつかにバインドされた文字列依存プロパティを更新しますTextBox.Text) 。

于 2012-11-26T08:49:43.323 に答える
0

あまつ そうです!私はまったく同じ問題を抱えていました。ボタンを作成し、MouseDown と PreviewMouseDown-Event を登録しました。イベントハンドラで、デバッグ用のメッセージボックスを表示しました。MouseDown-Event ではなく、PreviewMouseDown-Event を取得する理由を常に考えていました。その理由はメッセージボックスでした。だから私は MessageBox を System.Diagnostic.WriteLine に変更し、すべてがうまくいきました:)

ありがとう!

于 2013-02-18T17:34:31.737 に答える