创建一个覆盖整个区域的控件,除了特定区域

时间:2018-03-27 18:08:48

标签: c# xaml uwp win-universal-app

我想创建一个覆盖整个区域的控件,除了特定区域。该特定区域将呈椭圆/矩形形状。像下面的概念

enter image description here

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

<Path Name="ShowcasePath" StrokeThickness="1" IsHitTestVisible="True">
    <Path.Data>
        <GeometryGroup>
            <EllipseGeometry RadiusX="100" RadiusY="50"/>
            <RectangleGeometry/>
        </GeometryGroup>
    </Path.Data>
</Path>
Centre的{​​{1}}和EllipseGeometry的{​​{1}}将在后面的代码中设置。

这种方法有两个问题

  1. 即使没有alpha值,填充颜色也是半透明的。最终颜色为透明白色。所以这不是一个真正的问题。
  2. 椭圆内的项目应该是完全正常的,椭圆外的项目应该是无效的。
  3. enter image description here

    是否有解决上述问题的想法?

    或这种控制的任何不同想法?

2 个答案:

答案 0 :(得分:1)

我认为你已经非常接近你的例子,至少我发现它没有任何问题。如果您尝试以下代码,您将看到它完全符合您的描述:

<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>

enter image description here

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

“将椭圆聚焦在元素上”功能可以很容易地解决这个问题:

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

启用/禁用所有其他元素功能最好在viewmodel中处理,或者如果你没有,可以这样:

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);
    }
}

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

enter image description here

答案 1 :(得分:0)

而不是试图获得一个&#34; Click-through&#34;您可以简单地将元素(在您的情况下为togglebutton)带到前面(基本上是其他所有内容,以便它可以点击)。 您可以通过以下任一方式执行此操作:

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

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

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