MSDNの記事が述べているように、ボタンクリックイベント「Visual Tree」をStackpanelにクリックしないのはなぜですか?
-
20-08-2019 - |
質問
MSDNの記事で WPFでルーティングされたイベントとコマンドを理解する, 、それは述べています
イベントは、ソース要素から視覚ツリーを泡立てて(伝播)、処理されるか、ルート要素に到達するまで。
ただし、この例では、ボタンをクリックすると、 親スタックパネルイベントによって処理されるように「視覚ツリーを泡立てる」ことはありません, 、つまり、ボタンをクリックするとイベントが発生しません。
なぜだめですか? 「バブリングアップ」とはどういう意味ですか そうでなければ?
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.";
}
}
}
解決
イベントが処理されるまで泡立ちます...
マウスのクリックでボタンが何かをするので、マウスイベントを吸収し、クリックベントに変えます。
Previewmousedownを使用すると、ボタンが実行される前にStackpanelが最初にイベントを受信することがわかります。プレビューイベントはトンネルダウンアプローチを使用します。
他のヒント
他の人が言ったように、それは MouseDown
イベントはによって処理されます Button
さらに泡立つ前に。これをリフレクターで見ることができます ButtonBase.OnMouseLeftButtonDown
:
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (this.ClickMode != ClickMode.Hover)
{
e.Handled = true;
// SNIP...
}
base.OnMouseLeftButtonDown(e);
}
1つの解決策は、aを聞くことです MouseDown
イベント、そしてイベントが処理されているかどうかは気にしないことを示します。でこれを行うことができます AddHandler
方法。ブールの過負荷があり、すでに処理されているイベントを聞くことができます。
XAMLにムーズダウンハンドラーを設定する代わりにどこかでこれを行う場合:
TheStackPanel.AddHandler(MouseDownEvent, new MouseButtonEventHandler(TheStackPanel_MouseDown), true);
あなたはすべてを受け取ります MouseDown
イベントオン TheStackPanel
, 、それらが処理されたかどうかに関係なく。
さらに、Stackpanelにイベントを受け取ってもらいたい場合は、Stackpanel Xamlを以下に変更します。
<StackPanel x:Name="TheStackPanel"
Background="Yellow"
Button.Click="TheStackPanel_MouseDown" />
とイベントの署名:
private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)
この場合、スタックパネルはボタンのクリックイベントを受け取ります。ただし、スタックパネル自体をクリックすると、ボタンクリックが特に耳を傾けるため、イベントは発生しません。
すべてのメッセージがキャプチャされているためです 処理 ボタンとメッセージが停止します メッセージが停止します そこに泡立ちます。答えはあなたの質問のテキストに正しいです:
イベントはソース要素から視覚ツリーを泡立てます(伝播) どちらかが処理されるまで または、ルート要素に到達します。
編集:
エドワード・タンガイ(OP)はこの答えについてコメントしました、そして、私はここで彼のコメントをコピーしています。
「ボタンがイベントを処理しているとは思わない。つまり、ボタンにクリックハンドラーがない、スタックパネルにクリックハンドラー(Mousedown)があります。ボタンはそれを処理せず、スタックパネルによって処理されます。
あなたが正しいです。ボタンは、そのコントロールでハンドラーHAが指定されていないため、Mousedownイベントを処理していません。
しかし、それから、ムーズダウンは何らかの形で特別です。少なくともWindowsフォームでは、描画とドラッグとしてアクションを開始するために使用されるため、コントロールがイベントを取得すると、ハンドラーが定義されていない場合でも、後続のすべてのマウスメッセージをトラップします。このトラップは、コントロールがキャプチャプロパティをTrueに設定すると行われ、その後のイベントがバブルアップするのを効果的に停止します。キャプチャプロパティは、MouseUpイベントを取得すると、WindowsフォームによってFalseに戻ります。
繰り返しますが、これはWindowsフォームで機能する方法です。これを再確認することをお勧めしますが、imhoこれがWPFで異なるはずです。
参照:seセクション「Windowsフォーム処理」 http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (ページの中央からわずかに下にスクロールします)。
注:バブルとトンネリングイベントに関する参照については、Arcturuの回答に関する私のコメントを参照してください。
ボタンイベントは、マウスダウンとマウスアップを抑制します。ボタンイベントは高レベルのイベントであり、フラグハンドルを与えるコードを少し持っているため、この問題を解決するためにこの原因を抑制します。
TheButton.AddHandler(
UIElement.MouseDownEvent,
new MouseButtonEventHandler(TheStackPanel_MouseDown),
true);