How do I make a custom UIElement-derived class that contains (and displays) other UIElements as children?

c#, custom-controls, rendering, uielement, wpf

Solution

The following class provides the absolute minimum in terms of layout and rendering of child elements:

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

It is not required to have a UIElementCollection. An alternative implementation could look like this:

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
}

Problem

Let's say I want to make a class that inherits directly from `UIElement` and is able to contain one or more [externally added] `UIElement`s as children - like `Panel`s and other container controls. It's obviously easy to have the class house a collection of `UIElement`s in some form or other, but how do I get them to be displayed / rendered along with my class? I assume they must be added to the visual tree as children of my own `UIElement` in some way (or, possibly, render them manually à la going via `VisualTreeHelper.GetDrawing` and do it using `OnRender`'s `DrawingContext`? But that seems clumsy). I do not want to know that I can - or should - inherit from more ready-made controls, like `FrameworkElement`, `Panel`, `ContentControl` etc (if anything, I want to know how they are implementing the displaying / rendering of externally added child elements, where applicable). I have my reasons for wanting to be as high up in the hierarchy as possible, so please don't give me any lectures on why it is a good thing to be XAML / WPF Framework 'compliant' etc.

Original source