#1,191 – Custom Element with a Single Child Element

Below is an example of a simple custom element that derives from FrameworkElement and includes a single child element (UIElement), set using the Child dependency property.

Here’s the full code for the custom element.  We do the following:

  • Override both Measure and Layout
  • Override VisualChildrenCount and GetVisualChild to respond indicating that we have a single child
  • Override Render to render the graphical portion of the control
  • Use AddVisualChildAddLogicalChild to indicate that the child element belongs to the parent element
    public class MyElement : FrameworkElement
    {
        private static FrameworkPropertyMetadata childMetadata =
                   new FrameworkPropertyMetadata(null,
                            FrameworkPropertyMetadataOptions.AffectsParentArrange,
                            new PropertyChangedCallback(OnChildChanged));

        public static void OnChildChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            MyElement thisElement = obj as MyElement;
            if (thisElement == null)
                throw new Exception("Child property must be attached to MyElement");

            // Remove old one
            Visual oldChild = e.OldValue as Visual;
            if (oldChild != null)
            {
                thisElement.RemoveVisualChild(oldChild);
                thisElement.RemoveLogicalChild(oldChild);
            }

            // Attach new one
            Visual newChild = e.NewValue as Visual;
            if (newChild != null)
            {
                thisElement.AddVisualChild(newChild);
                thisElement.AddLogicalChild(newChild);
            }
        }

        public static readonly DependencyProperty ChildProperty =
            DependencyProperty.RegisterAttached("Child", typeof(UIElement),
                typeof(MyElement), childMetadata);

        public static void SetChild(DependencyObject depObj, UIElement value)
        {
            depObj.SetValue(ChildProperty, value);
        }

        protected override int VisualChildrenCount
        {
            get
            {
                UIElement childElement = (UIElement)GetValue(ChildProperty);
                return childElement != null ? 1 : 0;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            // (ignoring index)
            return (UIElement)GetValue(ChildProperty);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            UIElement childElement = (UIElement)GetValue(ChildProperty);
            if (childElement != null)
                childElement.Measure(availableSize);

            // "X" and child both use all of the available space
            return availableSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            UIElement childElement = (UIElement)GetValue(ChildProperty);
            if (childElement != null)
                childElement.Arrange(new Rect(new Point(0.0, 0.0), finalSize));

            return finalSize;
        }

        // Render a big "X"
        protected override void OnRender(DrawingContext dc)
        {
            dc.DrawLine(new Pen(Brushes.Blue, 2.0),
                new Point(0.0, 0.0),
                new Point(ActualWidth, ActualHeight));
            dc.DrawLine(new Pen(Brushes.Green, 2.0),
                new Point(ActualWidth, 0.0),
                new Point(0.0, ActualHeight));
        }
    }

We can now use this element as follows:

    <Grid>
        <loc:MyElement>
            <loc:MyElement.Child>
                <Label Content="I'm the child" HorizontalAlignment="Center"/>
            </loc:MyElement.Child>
        </loc:MyElement>
    </Grid>

When rendered, it looks like this:

1191-001

About Sean
Software developer in the Twin Cities area, passionate about .NET technologies. Equally passionate about my own personal projects related to family history and preservation of family stories and photos.

One Response to #1,191 – Custom Element with a Single Child Element

  1. Pingback: Dew Drop – October 30, 2014 (#1888) | Morning Dew

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: