Wpf 鼠标事件是否可以/应该冒泡?
在任何情况下都可能使MouseEnter事件冒泡吗 MSDN表示,这是一个附带的带有直接路由策略的事件,技术上排除了这种可能性。我有一个相当复杂的控件(本质上是由网格、堆栈面板和内容控件组成的层次结构)。我似乎从下至上传播MouseEnter事件,下面是从OnMouseEnter处理程序获取的调试转储(我在层次结构的不同级别包含了相同的自定义控件,用于处理MouseEnter,因此我有一个中心位置来侦听该事件): 输入:父级:s7b,时间戳:37989609 输入:父项:s2,时间戳:37989609 在:父:根,时间戳:37989609 s7b、s2和Root是框架元素名称,timestamp是来自MosueEnter事件的timestamp 如果路由策略是直接的,WPF如何决定事件发起人?它是否遍历可视树,直到找到第一个带有附加MouseEnter事件的FrameworkElement 当我正在为这个问题做一个最低限度的重新设置时,有人能建议是什么导致了这种行为吗Wpf 鼠标事件是否可以/应该冒泡?,wpf,wpf-controls,routed-events,Wpf,Wpf Controls,Routed Events,在任何情况下都可能使MouseEnter事件冒泡吗 MSDN表示,这是一个附带的带有直接路由策略的事件,技术上排除了这种可能性。我有一个相当复杂的控件(本质上是由网格、堆栈面板和内容控件组成的层次结构)。我似乎从下至上传播MouseEnter事件,下面是从OnMouseEnter处理程序获取的调试转储(我在层次结构的不同级别包含了相同的自定义控件,用于处理MouseEnter,因此我有一个中心位置来侦听该事件): 输入:父级:s7b,时间戳:37989609 输入:父项:s2,时间戳:37989
这是报告:
为了重现这个问题,只需将鼠标悬停在最右边的灰色方框上,并查看调试输出窗口,您将在其中看到三个条目,而我只希望看到一个条目
干杯。因为这是一个复杂的控件,所以当您用鼠标输入根元素时,很可能同时也在输入s7b和s2。由于这三个元素都是为MouseEnter事件注册的,因此如果鼠标可以同时输入这三个元素,则它们应该完全同时响应 该事件可能出现在可视化树上,因为您碰巧为一行大小相似的可视化父对象注册了MouseEnter。如果我在StackPanel中定义一个按钮,该按钮拉伸以填充StackPanel,并为MouseEnter事件注册这两个按钮,那么无论何时鼠标进入按钮,默认情况下它也将进入父级(StackPanel)。在这种情况下,事件可能看起来像是在可视化树上冒泡,而实际上它只是同时发生的两个独立元素的直接事件 如果要创建复杂控件,通常需要对整个控件进行一次MouseEnter回调,或对控件的特定部分进行特定的MouseEnter回调。是否确实需要对整个控件以及控件的各个部分进行回调 -编辑 刚刚看到你的新帖子。我尝试了你的代码,我注意到内容MyContentControl实例都是嵌套的。由于MyContentControl类派生自content control,因此正在拉伸控件以适应可用空间。您可以通过向MyContentControl类添加border属性来看到这一点。由于MyContentControl的背景默认为空,因此只有在触摸其中一个灰色框时才会触发鼠标
第一个MyContentControl创建一个水平堆叠面板,并添加灰色框,然后添加内容呈现器。网格右侧带有第一个灰色框的任何内容都将自动位于c2和/或c3中,因为c1中的内容呈现器将被拉伸以适合具有固定高度和宽度的窗口大小。这就是为什么当您将鼠标悬停在c2上时,会得到c1和c2的鼠标指针,因为当触摸灰色框时,鼠标已进入c1的内容呈现器,并且鼠标也已进入c2的灰色框。类似的逻辑可以用来理解c3的情况。鼠标透明控件(MTC)(我倾向于称之为布局控件)具有鼠标不透明子级(MOC)无法正确处理鼠标事件 我可能错了,但在我看来这是个错误。我可以猜测,罪魁祸首是MTC无法处理鼠标输入,但却假装这样做相当不协调 由于附加事件的优点,MTC成为鼠标事件的源和原始源,并且它们的IsMouseOver设置为true,这与系统的其他部分不太协调 解决方法是-只订阅控件中鼠标不透明部分的鼠标事件。乍一看,这听起来很可怕,但如果您使用命令,您不应该失去太多的灵活性
非常感谢您的建议。也许更详细的描述会有所帮助。在on
Mouse.MouseEnter
尽管此事件用于跟踪鼠标何时进入元素,但它也报告此元素的IsMouseOver属性已从false更改为true
MSDN说当IsMouseOver
从false变为true时,Mouse.MouseEnter
会触发。查看forIsMouseOver
的报价如下:
获取一个值,该值指示鼠标指针是否位于此元素上(包括其边界内的可视子元素)
我们都同意,空背景不支持交互。关于IsMouseOver
,有许多警告,但从实际应用中可以明显看出,该值不会在空背景下切换。但是,该定义确实指出,如果鼠标“位于”元素边界内的任何可视子对象上,则IsMouseOver
将改变,除非出现几个奇怪的cav
public class MyContentControl : ContentControl
{
static MyContentControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyContentControl),
new FrameworkPropertyMetadata(typeof(MyContentControl)));
}
protected override void OnMouseEnter(MouseEventArgs e)
{
if (e.Source == e.OriginalSource
&& e.Source is MyContentControl)
{
Debug.Write(string.Format("mouseenter:{0}, timestamp:{1}\n",
(e.Source as MyContentControl).Name,
e.Timestamp));
}
base.OnMouseEnter(e);
}
}
<Style TargetType="{x:Type local:MyContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyContentControl}">
<StackPanel Orientation="Horizontal">
<local:MouseEventReceiver />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
public class MouseEventReceiver : Control
{
static MouseEventReceiver()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MouseEventReceiver),
new FrameworkPropertyMetadata(typeof(MouseEventReceiver)));
}
}
<Style TargetType="{x:Type local:MouseEventReceiver}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="LightGray" Width="20" Height="20" Margin="5"></Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Window x:Class="MouseTricks.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MouseTricks"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:MyContentControl x:Name="c1">
<local:MyContentControl x:Name="c2">
<local:MyContentControl x:Name="c3" />
</local:MyContentControl>
</local:MyContentControl>
</Grid>
</Window>
private void MouseMove_Callback(Object sender, MouseEventArgs e)
{
if (c1.IsMouseOver)
MessageBox.Show("Mouse is Over c1!");
}