鼠标事件没有冒泡上来

3

我有两个相交的矩形。当鼠标悬停在它们上面时,我希望它们两个的不透明度都能改变。当鼠标悬停在其中一个矩形上时,这个功能是有效的。但是当鼠标悬停在矩形的交叉区域上时,只有上面的矩形改变了不透明度。请问如何让这种情况下两个矩形的不透明度都能改变?

<Window x:Class="WpfTestApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfTestApp="clr-namespace:WpfTestApp" Title="MainWindow" Height="350" Width="525" >
<Window.Resources>
    <Style x:Key="RectangleHighlighter" TargetType="{x:Type Rectangle}">
        <Setter Property="Opacity" Value="0.25" />
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Opacity" Value="1" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

    <Grid x:Name="LayoutRoot">
        <Rectangle Stroke="Black" Width="100" Fill="Green" Height="1000" Margin="0,15,0,0" Style="{StaticResource RectangleHighlighter}"/>
        <Rectangle Stroke="Black" Width="1000" Fill="Green" Height="100" Margin="0,15,0,0" Style="{StaticResource RectangleHighlighter}"/>
    </Grid>
</Window>
3个回答

2
实际上,HiTech Magic所描述的方法类似于以下方法:
<Window.Resources>
    <Style x:Key="RectangleHighlighter" TargetType="{x:Type Rectangle}">
        <Setter Property="Opacity" Value="0.25" />
        <Style.Triggers>
            <Trigger Property="Tag" Value="MouseOver">
                <Setter Property="Opacity" Value="1" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid x:Name="LayoutRoot" Background="Transparent" MouseMove="LayoutRoot_MouseMove">
    <Rectangle Stroke="Black" Width="100" Fill="Green" Height="1000" Margin="0,15,0,0" Style="{StaticResource RectangleHighlighter}"/>
    <Rectangle Stroke="Black" Width="1000" Fill="Green" Height="100" Margin="0,15,0,0" Style="{StaticResource RectangleHighlighter}"/>
</Grid>

以下是它的代码:

    private List<DependencyObject> hitResultsList = new List<DependencyObject>();

    private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
    {
        // Retrieve the coordinate of the mouse position.
        Point pt = e.GetPosition((UIElement)sender);

        // Clear the contents of the list used for hit test results.
        hitResultsList.Clear();

        // Set up a callback to receive the hit test result enumeration.
        VisualTreeHelper.HitTest(LayoutRoot, null,
            new HitTestResultCallback(MyHitTestResult),
            new PointHitTestParameters(pt));

        // Unset all children
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(LayoutRoot); ++i)
        {
            var element = VisualTreeHelper.GetChild(LayoutRoot, i) as FrameworkElement;
            if (element != null)
            {
                element.Tag = null;
            }
        }

        // Perform actions on the hit test results list.
        foreach (var dependencyObject in hitResultsList)
        {
            var element = dependencyObject as FrameworkElement;
            if (element != null)
            {
                element.Tag = "MouseOver";
            }
        }
    }

    // Return the result of the hit test to the callback.
    public HitTestResultBehavior MyHitTestResult(HitTestResult result)
    {
        // Add the hit test result to the list that will be processed after the enumeration.
        hitResultsList.Add(result.VisualHit);

        // Set the behavior to return visuals at all z-order levels.
        return HitTestResultBehavior.Continue;
    }

当然,对于这种情况最好添加一些特殊的附加属性和行为。

感谢Kreol的回复。正如我在对HiTech的评论中提到的,我更倾向于使用仅限XAML的解决方案。如果您能提供一个仅限XAML的解决方案,那就太好了,否则我会尝试这个方法。 - Souvik Basu
很遗憾,我猜这个任务没有“仅限XAML”的解决方案。所以我建议你将所有这些代码分离到一个特殊的附加属性(行为)中,用于容器控件,并且当然添加一些附加属性来代替在我的示例中使用的标签。这样,您就可以在XAML中使用这些附加属性而无需使用代码后台。 - Kreol

1

你需要将悬停处理程序添加到父网格中,使两个矩形的IsHitTestVisible属性为False,并使用VisualTreeHelper.FindElementsInHostCoordinates来确定实际在鼠标下方的对象(一个或多个)。

如果你一定要基于样式实现,Mario Vernari的建议可以实现,但是悬停会在整个网格上触发,而不仅仅是在矩形上。

这对于一个附加的行为来说是一个非常有用的想法。该行为将实现上述代码,但会在子对象上触发悬停事件,因此你仍然可以使用样式...我得试一试。


感谢 HiTech 的回复。我更倾向于使用仅限 XAML 的解决方案。你能提供一些建议吗?如果不行的话,我会尝试这个方法。 - Souvik Basu
1
@Souvik Basu:仅限Xaml意味着您需要通过一些新的方式来模拟现有事件。我建议尝试创建一个行为来生成事件(或状态更改)。 - iCollect.it Ltd

0
尝试将样式应用于网格元素。

感谢Mario的回复。但是这并不能满足我的需求,因为我只想在鼠标悬停在矩形上时突出显示它们,而不是在网格上方。 - Souvik Basu
这个网格没有背景颜色(即null),因此所有鼠标事件都无法捕获。如果你试图将鼠标悬停在矩形框之外的区域,就不会有淡入淡出效果(也不会触发事件)。然而,除非你保持背景为null,“透明”并不等同于它。 - Mario Vernari
注意:我现在已经在WPF上尝试过了,它完美地运行。但是,我没有尝试过Silverlight。 - Mario Vernari
当我在网格上设置样式而不是矩形时,当我悬停在其中任何一个上时,两个矩形都会被突出显示。如果我悬停在特定的矩形上,我只想突出显示那个矩形。如果我悬停在交叉点上,我希望两个矩形都能突出显示。 - Souvik Basu
哦哦!我误解了你的目标,抱歉! - Mario Vernari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接