Why does the Parent property of a container of an ItemsControl return null and not the Panel it sits on?
Asked Answered
Q

2

13

This one has me stumped. We have a custom ItemsControl which uses both custom containers as well as a custom panel as its ItemsHost. Now the panel has some metrics that the containers need for rendering purposes. Since they are direct children of the panel in the visual tree, you'd think that the Parent property of the container would return the panel, but it doesn't!

I have also confirmed this exact thing using Snoop on a standard ListBox so this isn't exclusive to our code, but apparently all containers of ItemsControls.

Now I know I can use the VisualTreeHelper to get the visual parent (which is what I need) but why would the parent not be the panel?

If the argument is that the panel is simply part of the Visual Tree and Parent is reserved for the Logical Tree, then wouldn't the parent be the ItemsControl?

If the argument there is the container too is part of the ItemsControl's visual tree and not the logical tree, then why would the contents hosted in the container return the container as its Parent property?

That means if you're walking the logical tree from a data item, you stop at the containers, which may explain why our bindings from the containers to the panels aren't working as expected. (I believe bindings are based on a logical hierarchy and not a visual one, but I'd have to test to be sure.)

Quizzical answered 2/1, 2013 at 7:35 Comment(3)
Good question, I've always wondered about that, too. Just a sidenote: You can also get the ItemsControl using ItemsControl.GetItemsOwner.Psychoneurosis
True, but you can't do that in a binding without explicitly writing a converter. Searching up the tree using RelativeSource seems to fail; my guess is for the exact reason I pointed out... the container's parent is Null.Quizzical
That is in deed a good question. I believe to read some where that a listboxitem has a non public member to get the parent. But if you uses custom containers then you would be responsible for setting the parent on creation.Irish
B
8

I never noticed that and this spiked my curiosity. After looking for clues in the .Net Framework in found that Parent property seems indeed to be set manualy: This required several steps but I found that the only way to change the parent property is to invoke these methods:

parent affectation

If I analyse for example the FrameworkElement.AddLogicalChild method, I found that these methods are using it:

FrameworkElement.AddLogicalChild analysis

This confirms that the parent property is supposed to refer to the logical tree. I tried to create my own custom control:

[ContentProperty("CustomContent")]
public class CustomControl1 : Control
{
    static CustomControl1()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
    }

    public object CustomContent
    {
        get { return GetValue(CustomContentProperty); }
        set { SetValue(CustomContentProperty, value); }
    }

    public static readonly DependencyProperty CustomContentProperty = DependencyProperty.Register("CustomContent", typeof(object), typeof(CustomControl1));
}

with this template:

<ControlTemplate TargetType="{x:Type local:CustomControl1}">
     <ContentPresenter ContentSource="CustomContent" />
</ControlTemplate>

I used it this way:

<WpfApplication1:CustomControl1 Width="50" Height="50">
    <Rectangle Fill="Red" />
</WpfApplication1:CustomControl1>

... this worked like this (like a charm :-)):

custom control screen caprute

... and guess what... Parent of the rectangle is not set :-)

I don't have time to continue investigating for now but regarding ItemsControl, I imagine that maybe the ItemContainerGenerator doesn't know the logical parent in which it inserts itemsContainers, that could explain why parent property is not set in this case... but that need to be proven...

Blisse answered 20/2, 2013 at 9:22 Comment(4)
Great research there! (...and sorry I didn't see this sooner.) And great detail too! More SO answers should be like this. Giving you the answer vote since this should be enough to answer the original question, and give direction to those who want to go deeper.Quizzical
your images seem to have gone missing. Any chance you can upload them directly? Without them the answer isn't as clear as it used to be.Quizzical
Thanks for your interest. But ??.. as far as I can see, the images are still displayedBlisse
My bad. Proxy issue at work where for some reason, they block images hosted on SO. They are in fact still there, and have been for two years now.Quizzical
L
6

The FrameworkElement.Parent property documentation says it may be null e.g. for items created in datatemplates. In such case they propose using FrameworkElement.TemplatedParent:

For templates, the Parent of the template eventually will be null. To get past this point and extend into the logical tree where the template is actually applied, use TemplatedParent.

May be it's your case? It helped me in similar case (I used Parent then if it's null used TemplateParent as fallback).

Yes, the answer is late but it may help others who stumbles on same error as me

Lacrosse answered 3/5, 2018 at 16:19 Comment(1)
If this is true, you just saved me a TON of work! Null-coalescing operator to the rescue!!Quizzical

© 2022 - 2024 — McMap. All rights reserved.