根据这篇 MSDN 文章(除其他外),
每当路由事件到达其路由中的元素实例时,在附加到该类实例的任何实例侦听器处理程序之前调用类处理程序。
我对RoutedEvent
s 很陌生,所以我的代码中可能有错误,但似乎附加到 a 的类处理程序RoutedEvent
被声明为RoutingStrategy.Tunnel
并不总是在附加到同一事件的实例处理程序之前触发。
在下面的示例中,我创建了一个TouchButton
带有隧道RoutedEvent
和冒泡的控件类RoutedEvent
。我已经为每个注册了类处理程序。然后,我在窗口中创建了该类的一个实例,并在后面的代码中处理每个事件。Grid
我在类元素和包含它的元素上都为隧道事件附加了相同的处理程序。所有四个处理程序都以 a 显示它们的名称,MessageBox
因此您可以清楚地看到执行顺序。
- 网格实例 PreviewTouch
- 类 TouchButton_PreviewTouch
- TouchButton 实例 PreviewTouch
- 类 TouchButton_Touch
- TouchButton 实例触摸
这意味着如果我调用e.Handled = true;
类PreviewTouch
事件处理程序,我可以停止执行到达所有其他事件处理程序,除了附加到Grid
元素的事件处理程序。这应该是这样,还是我在某个地方犯了错误?否则,如何阻止执行到达每个实例事件处理程序?
这是课程:
public class TouchButton : Button
{
static TouchButton()
{
EventManager.RegisterClassHandler(typeof(TouchButton), PreviewTouchEvent,
new RoutedEventHandler(TouchButton_PreviewTouch), true);
EventManager.RegisterClassHandler(typeof(TouchButton), TouchEvent,
new RoutedEventHandler(TouchButton_Touch), true);
}
private static void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
{
MessageBox.Show("Class TouchButton_PreviewTouch");
}
private static void TouchButton_Touch(object sender, RoutedEventArgs e)
{
MessageBox.Show("Class TouchButton_Touch");
}
public static RoutedEvent TouchEvent = EventManager.RegisterRoutedEvent("Touch",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TouchButton));
public event RoutedEventHandler Touch
{
add { AddHandler(TouchEvent, value); }
remove { RemoveHandler(TouchEvent, value); }
}
public static RoutedEvent PreviewTouchEvent = EventManager.RegisterRoutedEvent(
"PreviewTouch", RoutingStrategy.Tunnel, typeof(RoutedEventHandler),
typeof(TouchButton));
public event RoutedEventHandler PreviewTouch
{
add { AddHandler(PreviewTouchEvent, value); }
remove { RemoveHandler(PreviewTouchEvent, value); }
}
protected override void OnClick()
{
RaiseTouchEvent();
}
private void RaiseTouchEvent()
{
RoutedEventArgs touchEventArgs = new RoutedEventArgs(PreviewTouchEvent);
RaiseEvent(touchEventArgs);
if (!touchEventArgs.Handled) RaiseEvent(new RoutedEventArgs(TouchEvent));
}
}
以下是后面窗口代码中的实例处理程序:
private void TouchButton_PreviewTouch(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0} Instance PreviewTouch",
((FrameworkElement)sender).Name));
}
private void TouchButton_Touch(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format("{0} Instance Touch",
((FrameworkElement)sender).Name));
}
这是控制 XAML:
<Grid Name="Grid" Controls:TouchButton.PreviewTouch="TouchButton_PreviewTouch">
<Controls:TouchButton x:Name="TouchButton" Width="200" Height="45" FontSize="24"
Content="Touch me" Touch="TouchButton_Touch" PreviewTouch="TouchButton_PreviewTouch" />
</Grid>
我确实知道隧道事件是Grid
在“隧道”到元素之前由元素处理的TouchButton
,但我认为类处理程序总是应该在实例处理程序之前触发。如果没有,我怎样才能做到这一点?
更新>>>
感谢@sanguine 的回答,我设法找到了一种方法来阻止所有实例处理程序处理事件。如果不是像 sanguine 建议的那样替换声明的类处理类型,而是将其替换为TouchButton
,那么它将捕获所有派生控件。Grid
FrameworkElement
FrameworkElement
EventManager.RegisterClassHandler(typeof(FrameworkElement), PreviewTouchEvent,
new RoutedEventHandler(TouchButton_PreviewTouch), true);