【问题标题】:Get the shape of a control as Geometry获取控件的形状为几何
【发布时间】:2011-10-25 08:17:10
【问题描述】:

有没有办法获取控件的形状并将其转换为Geometry 对象?

我有以下情况:在 WPF 应用程序中将显示一个弹出窗口。这个弹出窗口没有窗口,它是一个控件,它将变得可见。应用程序的其余部分会变暗,因为灰色层位于应用程序上方。

现在的问题是这个灰色层也在弹出窗口本身的上方,这是由应用程序的设计造成的,加上被点击并打开弹出窗口的元素也不应该被该层隐藏。我决定在灰色层上附加一个剪裁几何,这很好,但我必须检测所有我不想自己隐藏的形式和路径。

回到我的问题:有没有办法获得控件的形状并将其转换为Geometry 对象?例如。我找到了获取控件的 VisualBrush 的方法,但也无法转换它 - 或者只是看不到它是如何实现的。

【问题讨论】:

  • 您是否尝试从弹出窗口中创建一个切口,以便灰色层不会覆盖它?如果是这样,您可以使用 Z-Order 控制组件的显示顺序:blogs.msdn.com/b/wpfsdk/archive/2006/06/13/…
  • 我会选择 Adorner/AdornerLayer 或 Popup 控件。这两个元素都旨在在其他控件之上显示信息,并且应该满足您在视觉内容上方显示弹出窗口而不剪切任何内容的需求。见msdn.microsoft.com/en-us/library/ms749018.aspxmsdn.microsoft.com/en-us/library/ms747117.aspx
  • 你们俩都是对的,对于弹出窗口,使用 Z-Index 或已经满足我需要的控件会容易得多。我将尝试使用其中一种可能性。但是源代码控制呢?被点击的按钮也不应该被弹出覆盖覆盖。
  • 我真的很想直接回答 OP 的问题。你能从 UIElement 中获取几何图形吗?

标签: c# wpf xaml


【解决方案1】:

你可以这样做: 从视觉树中移除按钮并将其放在装饰器上。 当装饰器关闭时,再次将其附加到原始父级。 我认为这比剪裁任何几何图形更加灵活,并且更加灵活(例如,您可以在装饰器上放置用户控件等复杂内容)

以下示例使用 Panel 作为按钮的容器。

Xaml(窗口):

<Grid Margin="50" x:Name="myGrid" Background="LightBlue">
<Button x:Name="myButton" Width="80" Height="30" Click="myButton_Click">Show popup</Button>

代码背后: 私有FrameworkElementAdorner _adorner; 私有面板_originalParent;

private void myButton_Click(object sender, RoutedEventArgs e)
{
  if (_adorner == null)
  {
    _adorner = new FrameworkElementAdorner(myGrid);
  }

  // remove the button from the parent panel and attach it to the adorner
  // otherwise remove from adorner and attach to original parent again
  if (_adorner.IsVisible)
  {
    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(myGrid);
    adornerLayer.Remove(_adorner);

    Panel parent = VisualTreeHelper.GetParent(myButton) as Panel;
    if (parent != null)
    {
      parent.Children.Remove(myButton);
    }
    _originalParent.Children.Add(myButton);
  }
  else
  {
    _originalParent = VisualTreeHelper.GetParent(myButton) as Panel;
    if (_originalParent != null)
    {
      _originalParent.Children.Remove(myButton);
    }

    // Create the Adorner with the original button in it
    _adorner.Child = CreateAdornerContent(myButton);

    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(myGrid);
    adornerLayer.Add(_adorner);
  }
}

/// <summary>
/// Creates some dummy content for the adorner
/// </summary>
private FrameworkElement CreateAdornerContent(Button myButton)
{
  Grid g = new Grid();
  g.Background = new SolidColorBrush(Colors.Yellow);

  TextBlock tb = new TextBlock();
  tb.Text = "I am the Adorner";

  g.Children.Add(tb);
  g.Children.Add(myButton);
  return g;
}

这里是一个简单的装饰器,它只显示一个框架元素: 类 FrameworkElementAdorner : 装饰器 { 私有 FrameworkElement _child;

public FrameworkElementAdorner(UIElement adornedElement)
  : base(adornedElement)
{
}

protected override int VisualChildrenCount
{
  get
  {
    return 1;
  }
}

protected override Visual GetVisualChild(int index)
{
  if (index != 0) throw new ArgumentOutOfRangeException();
  return _child;
}

public FrameworkElement Child
{
  get
  {
    return _child;
  }
  set
  {
    if (_child != null)
    {
      RemoveVisualChild(_child);
    }
    _child = value;
    if (_child != null)
    {
      AddVisualChild(_child);
    }
  }
}

protected override Size ArrangeOverride(Size finalSize)
{
  _child.Arrange(new Rect(new Point(0, 0), finalSize));
  return new Size(_child.ActualWidth, _child.ActualHeight);
}

}

如果你愿意,我也可以上传完整的 sln。这可能以某种方式在这里吗?

【讨论】:

  • +1 作为您的答案,因为它肯定会起作用并且是一个简单的解决方案。不幸的是,我无法修改可视化树,因为我们使用的是框架并且客户的严格规范不允许这样做。我将不得不对底层控件使用裁剪方法。将弹出框放在ZIndex较高的层中,只能显示不剪裁的弹出框本身,但无法修改位于较深层上的控件。
  • 将此标记为答案,因为您做得非常好。这不是我想要的,但可以帮助其他人。谢谢!
猜你喜欢
  • 2020-10-15
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
相关资源
最近更新 更多