创建一个覆盖除特定区域以外的整个区域的控件

Creating a control that covers the whole area except a particular area

我想创建一个覆盖除特定区域以外的整个区域的控件。该特定区域将呈 ellipse/rectangle 形状。类似于下面的概念

我的想法是使用路径。下面是我的路径代码。

<Path Name="ShowcasePath" StrokeThickness="1" IsHitTestVisible="True">
    <Path.Data>
        <GeometryGroup>
            <EllipseGeometry RadiusX="100" RadiusY="50"/>
            <RectangleGeometry/>
        </GeometryGroup>
    </Path.Data>
</Path>
EllipseGeometry

CentreRectangleGeometryRect将在后面的代码中设置。

这个方法有两个问题

  1. 即使没有 alpha 值,填充颜色也是半透明的。最终颜色将是透明的白色。所以这不是一个真正的问题。
  2. 椭圆内的项目应该功能齐全,椭圆外的项目应该没有功能。

有解决上述问题的办法吗?

或者这个控件有什么不同的想法吗?

您无需尝试获取 "Click-through" 元素,只需将元素(在您的情况下为切换按钮)置于最前面(基本上位于其他所有元素之上,以便可以点击)。 您可以通过以下任一方式执行此操作:

  1. 更改元素的 ZIndexProperty 使其位于最前面。 YourElement.SetValue(Canvas.ZIndexProperty, index);
  2. 删除元素并再次添加到父网格(因此它基本上是最后添加的元素)

    parentGrid.Children.Remove(YourElement); parentGrid.Children.Add(YourElement); parentGrid.UpdateLayout();

用户与控件成功交互后,您可以将其切换回之前的状态。希望这对您有所帮助。

我认为您的示例已经非常接近了,至少我找不到任何问题。如果您尝试以下代码,您会发现它完全符合您的描述:

<Grid>
    <Button Content="Clickable" HorizontalAlignment="Left" 
      Margin="113,90,0,0" VerticalAlignment="Top" Width="75"/>
    <Button Content="Non-Clickable" HorizontalAlignment="Left" 
      Margin="272,90,0,0" VerticalAlignment="Top" Width="75"/>
    <Path Name="ShowcasePath" StrokeThickness="1" Fill="#88ff0000" IsHitTestVisible="True">
        <Path.Data>
            <GeometryGroup FillRule="EvenOdd">
                <EllipseGeometry Center="150,100" RadiusX="100" RadiusY="50"/>
                <RectangleGeometry Rect="0,0,500,500"/>
            </GeometryGroup>
        </Path.Data>
    </Path>
</Grid>

但是请记住,用户仍然可以使用 Tab 更改焦点元素并使用 Space 或激活元素Return,即使您将 IsHitTestVisible 设置为 false

"focus the ellipse on an element" 功能可以像这样轻松处理:

public void FocusOnElement(FrameworkElement element)
{
    Point center = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
    Point newPosition = element.TranslatePoint(center, ShowcasePath);
    ellipseGeometry.Center = newPosition;
}

enable/disable 所有其他元素的功能最好在您的视图模型中处理,或者如果您没有,有点像这样:

private void DiableAllButThisAndItsParents(FrameworkElement thisElement)
{
    List<FrameworkElement> hierarchy = FindParents(thisElement).ToList();

    foreach (FrameworkElement element in hierarchy)
    {
        element.IsEnabled = true;

        if (ReferenceEquals(element, thisElement)) continue;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            var child = VisualTreeHelper.GetChild(element, i);
            if (!(child is FrameworkElement childElement)) continue;

            childElement.IsEnabled = hierarchy.Contains(childElement);
        }
    }
}

private IEnumerable<FrameworkElement> FindParents(FrameworkElement element)
{
    DependencyObject current = element;

    while (current != null)
    {
        if (current is FrameworkElement)
            yield return (FrameworkElement) current;
        current = VisualTreeHelper.GetParent(current);
    }
}

把它们放在一起,它应该看起来像这样: