【问题标题】:Creating a control that covers the whole area except a particular area创建一个覆盖除特定区域之外的整个区域的控件
【发布时间】:2018-03-27 18:08:47
【问题描述】:

我想创建一个覆盖除特定区域之外的整个区域的控件。该特定区域将呈椭圆形/矩形。类似于下面的概念

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

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

EllipseGeometry 中的CentreRectangleGeometry 中的Rect 将在后面的代码中设置。

这个方法有两个问题

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

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

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

【问题讨论】:

  • 那个巨大的红色盒子真的很碍眼!
  • @RonBeyer 最终的颜色将是透明的白色。
  • 我知道这只是您想要覆盖的模型,很难看(至少在我的 LCD 上)。也许更好的选择是绑定其他所有内容的Visibility,以便将您想要显示的内容以外的所有内容设置为隐藏?
  • @RonBeyer 不,所有控件都应该通过半透明的白色可见。所以我不能将Visibility 设置为这样。
  • 绑定所有控件'a(除了你要保持活动的那个)IsEnabled属性,然后在需要时将其设置为False。快乐编码:)

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


【解决方案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>

但请记住,即使您将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;
}

启用/禁用所有其他元素功能最好在您的视图模型中处理,或者如果您没有,则如下所示:

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

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

【讨论】:

  • 我不想惹IsEnabled,因为它会改变外观
  • @VijayNirmal 当然,您可以使用上述技术的任意组合。
  • IsHitTestVisible 工作正常。昨天,它没有工作。但我的方法的另一个问题是,椭圆内的每个控件都是难以处理的。假设我有一个按钮 1 和按钮 2 彼此靠近,那么即使按钮 1 被突出显示,我们仍然可以单击按钮 2。
【解决方案2】:

您可以简单地将元素(在您的情况下为切换按钮)带到前面(基本上高于其他所有内容,以便它可以点击),而不是尝试获取“点击”元素。 您可以通过以下任一方式执行此操作:

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

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

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

【讨论】:

  • 期待突出显示的项目,应关闭所有项目的交互。另外,我想创建一个自定义控件。
猜你喜欢
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 2017-12-21
  • 2021-01-09
  • 1970-01-01
相关资源
最近更新 更多