【问题标题】:How do I make a custom UIElement-derived class that contains (and displays) other UIElements as children?如何制作包含(并显示)其他 UIElement 作为子级的自定义 UIElement 派生类?
【发布时间】:2013-12-18 17:40:32
【问题描述】:

假设我想创建一个直接从UIElement 继承的类,并且能够包含一个或多个[外部添加的]UIElements 作为子级 - 例如Panels 和其他容器控件。显然很容易让班级以某种形式收集UIElements,但是如何让它们与我的班级一起显示/呈现?

我认为它们必须以某种方式作为我自己的UIElement 的子级添加到可视化树中(或者,可能,通过VisualTreeHelper.GetDrawing 手动渲染它们并使用OnRender 的@987654328 来完成@? 但这似乎很笨拙)。

我确实想知道我可以(或应该)从更多现成的控件继承,例如 FrameworkElementPanelContentControl 等(如果有的话,我想要了解他们如何实现外部添加的子元素的显示/渲染(如果适用)。

我有理由希望在层次结构中尽可能高,所以请不要给我任何关于为什么 XAML / WPF 框架“兼容”等是一件好事的讲座。

【问题讨论】:

  • 用 Reflector 之类的检查PresentationFramework.dll
  • 大声笑 - 我是这个接近添加“你听到了吗,HighCore?”在最后一段的末尾(在我注意到有评论之前......但你打败了我)。
  • 不记得我是否对你说过,但是,是的,你是一个经过实验的开发人员,他真的 knows 他在做什么,但对于大多数使用 WPF 的人来说,情况恰恰相反.这就是为什么我有这种陈词滥调的“删除所有代码并学习 MVVM”的东西不断地一次又一次地出现。当然,这不适用于您和其他专业的 WPF/XAML 开发人员

标签: c# wpf custom-controls rendering uielement


【解决方案1】:

以下类在子元素的布局和渲染方面提供了绝对最小值:

public class UIElementContainer : UIElement
{
    private readonly UIElementCollection children;

    public UIElementContainer()
    {
        children = new UIElementCollection(this, null);
    }

    public void AddChild(UIElement element)
    {
        children.Add(element);
    }

    public void RemoveChild(UIElement element)
    {
        children.Remove(element);
    }

    protected override int VisualChildrenCount
    {
        get { return children.Count; }
    }

    protected override Visual GetVisualChild(int index)
    {
        return children[index];
    }

    protected override Size MeasureCore(Size availableSize)
    {
        foreach (UIElement element in children)
        {
            element.Measure(availableSize);
        }

        return new Size();
    }

    protected override void ArrangeCore(Rect finalRect)
    {
        foreach (UIElement element in children)
        {
            element.Arrange(finalRect);
        }
    }
}

不需要有 UIElementCollection。另一种实现可能如下所示:

public class UIElementContainer : UIElement
{
    private readonly List<UIElement> children = new List<UIElement>();

    public void AddChild(UIElement element)
    {
        children.Add(element);
        AddVisualChild(element);
    }

    public void RemoveChild(UIElement element)
    {
        if (children.Remove(element))
        {
            RemoveVisualChild(element);
        }
    }

    // plus the four overrides
}

【讨论】:

  • 不,您也可以使用普通列表并调用 Add/RemoveVisualChild 来设置可视化树。神奇之处在于四个覆盖。
  • 太好了,这正是我想要的(关于我之前的评论:有那么一秒,我想也许孩子的处理嵌入在 UIElementCollection 中,因为它被初始化为 this - 我认为这可能意味着它与视觉树等进行了连接)。其中有多少真正源于Visual
  • 名称中包含 Visual 的所有内容:Add/RemoveVisualChild、VisualChildrenCount 和 GetVisualChild。 UIElement 添加 MeasureCore 和 ArrangeCore。
  • ..但是从 Visual 继承在实践中是没有用的,对吧?我在某处读到它的实际渲染机制是Internal,因此只能通过其后代之一间接访问它们..?
  • 好吧,我有一个非常实用的用例,我从 ContainerVisual 和 DrawingVisual 派生。您可以查看我在 CodePlex 上的XAML Map Control 中的 TileContainer 和 TileLayer 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多