【发布时间】:2011-02-17 13:54:57
【问题描述】:
我对此感到困惑:
我做了一个很简单的例子:
MainWindow.xaml:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="RichTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RichTextBox">
<Grid Height="100" Width="200">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Background="Blue" Grid.Row="0">Label</Label>
<Border PreviewMouseDown="Border_PreviewMouseDown" Background="Red" Grid.Row="1">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<RichTextBox>
<FlowDocument>
<FlowDocument.Blocks>
<Paragraph>
oaizeropiazuerpoaizeurpoaizeurpaozieurpaozieru
</Paragraph>
</FlowDocument.Blocks>
</FlowDocument>
</RichTextBox>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
namespace Test
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Border_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("Click !");
}
}
}
现在,当我明确地将 PreviewMouseDown EventHandler 放在边框上而不是在模板中的标签上时,我希望它会在我单击控件的(红色)边框时触发,但不会在我单击(蓝色)标签。
但是,当我点击(红色)边框AND时,当我点击(蓝色)标签时,会触发该事件。
那么为什么 Label 会调用我明确附加到 controlTemplate 的另一部分(即:边框)的 EventHandler?
我已检查:如果我从边框属性中删除 PreviewMouseDown="Border_PreviewMouseDown" 代码,则不会再在标签上触发事件。
我在这里错过了什么?
什么是正确的做法?如何设计我的 controlTemplate 以便仅由模板化控件的子部分触发 PreviewMouseDown 事件?
提前致谢
编辑:按照 Snowbear 的回答,我在单击标签时检查了事件的 originalSource。这确实是边界。为什么会这样?边框以什么方式封装了上面模板中的标签?为了避免这种情况,我专门将它们设置在不同的网格行上,那怎么会呢?
Edit2 只是为了好玩,我创建了一个只打印事件的发送者/来源/原始来源的处理程序,并将其附加到模板中的网格、边框和滚动查看器。
这是我在垂直滚动条上单击一次(且仅一次)时得到的结果:
Clic -- Sender: System.Windows.Controls.Grid -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: MyRichTextBox
Clic -- Sender: System.Windows.Controls.Border -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: MyRichTextBox
Clic -- Sender: System.Windows.Controls.ScrollViewer -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: MyRichTextBox
Clic -- Sender: System.Windows.Controls.Grid -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: System.Windows.Controls.ScrollViewer
Clic -- Sender: System.Windows.Controls.Border -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: System.Windows.Controls.ScrollViewer
Clic -- Sender: System.Windows.Controls.ScrollViewer -- OriginalSource: Microsoft.Windows.Themes.ScrollChrome -- Source: System.Windows.Controls.ScrollViewer
这清楚地解决了问题:由于某种原因,事件确实被隧道化了两次,首先以 TemplatedParent(即:RichtextBox)作为源,然后以 contentPresenter(即:ScrollViewer)作为源。
Merlin 最宽松的裤子,我真的很想知道编写这个程序的 MS Dev 的脑袋是怎么想的……
【问题讨论】:
标签: wpf event-handling