Search code examples
c#wpfxamlwpf-controlslogical-tree

Building a logical tree for a custom control


I'm working on a control that has an ObservableCollection as one of its DependencyProperties. This property is set as the DefaultProperty for my control, so I can implicitly add items to the collection in XAML by constructing lines similar to the following:

<MyControl>
    <MyItem/>
    <MyItem/>
    <MyItem/>
</MyControl>

As far as I understand, the WPF engine builds the logical tree when it parses through the XAML. Therefore, each MyItem should be a logical child of the MyControl. Conversely, the MyControl should be the logical parent of each MyItem.

Well, apparently there is more to it. Below is the code that I use to define the relationship above. The custom control contains a DependencyProperty for the ObservableCollection and it is backed by a CLR-property.

[ContentProperty("Items")]
public class MyControl : Control
{
    public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
        "Items", 
        typeof(ObservableCollection<MyItem>), 
        typeof(MyControl), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnItemsChangedProperty));

    [Category("MyControl")]
    public ObservableCollection<MyItem> Items
    {
        get { return (ObservableCollection<MyItem>)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
    }

    public MyControl() : base()
    {   //Set a new collection per control, but don't destroy binding.
        SetCurrentValue(ItemsProperty, new ObservableCollection<MyItem>());
    }
}

From with the MyItem (which inherits FrameworkContentElement), I attempt to access its logical parent like so:

if (Parent is FrameworkElement)
{    //Re-Render the parent control.
    ((FrameworkElement)Parent).InvalidateVisual();
}

To my surprise, the parent control is never re-rendered. This is because the MyItem.Parent property is null. Why is this?

How can I instruct the WPF engine to know that MyControl should be the logical parent to MyItem?


Solution

  • If this is for a chart control with multiple graphs, you're definitely in ItemsControl land. You may want to have a look at what you can build from WPFToolkit or one of the other tools listed here:

    https://stackoverflow.com/a/4227432/1869660

    As for your actual question, if you really need to add MyItems to your logical tree manually, you need to call AddLogicalChild(), for example somewhere in your OnItemsChangedProperty event. There is an example on MSDN.