Why does binding fail when binding a child element to another element when the parent succeeds?

久未见 提交于 2019-12-22 19:24:55

问题


Say I have two classes that can reference a third UI object (in this example a button).

In addition, the parent class can contain an element of the child class.

If they both are bound to the same control, the same way, the child will fail but the parent succeed.

Is this a bug in WPF?


The parent :

class MyFrameworkElement : FrameworkElement
{
    // A depenedency property that will contain a child element sub-element
    private static readonly DependencyProperty ChildElementProperty =
                    DependencyProperty.Register("ChildElement",
                    typeof(MyChildElement),
                    typeof(MyFrameworkElement),
                    new PropertyMetadata());

    [Category("ChildProperties")]
    public MyChildElement ChildElement
    {
        set { SetValue(ChildElementProperty, value); }
        get { return (MyChildElement)GetValue(ChildElementProperty); }
    }


    // Now, a reference to some other control, in this case we will bind a button to it!
    public UIElement ButtonReferenceInParent
    {
        get { return (UIElement)GetValue(ButtonReferenceInParentProperty); }
        set { SetValue(ButtonReferenceInParentProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ButtonReferenceInParent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ButtonReferenceInParentProperty =
        DependencyProperty.Register("ButtonReferenceInParent", typeof(UIElement), typeof(MyFrameworkElement), new UIPropertyMetadata(null));

And then the child :

public class MyChildElement : FrameworkElement
{
    public UIElement ButtonReferenceInChild
    {
        get { return (UIElement)GetValue(ButtonReferenceInChildProperty); }
        set { SetValue(ButtonReferenceInChildProperty, value); }
    }

    public static readonly DependencyProperty ButtonReferenceInChildProperty =
        DependencyProperty.Register("ButtonReferenceInChild", typeof(UIElement), typeof(MyChildElement), new UIPropertyMetadata(null));
}

OK -

Now say I Add them to my XAML like this :

<Grid>
    <my:MyFrameworkElement x:Name="ParentName" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ButtonReferenceInParent="{Binding ElementName=buttonisme}">
        <my:MyFrameworkElement.ChildElement>
            <my:MyChildElement x:Name="ChildName" ButtonReferenceInChild="{Binding ElementName=buttonisme}"/>
        </my:MyFrameworkElement.ChildElement>
    </my:MyFrameworkElement>

    <Button x:Name="buttonisme" Click="buttonisme_Click" />
</Grid>

Why does the binding work on the parent but then fail on the child, when I am using the EXACT same notation?


Here is my test code...

     Console.WriteLine("Parent button reference is {0}", ParentName.ButtonReferenceInParent);

        if (ChildName.ButtonReferenceInChild == null)
        {
            Console.WriteLine("Child button reference is null!");
        } 
        else
        {
            Console.WriteLine("Child button is {0}", ChildName.ButtonReferenceInChild);
        }

And here is the test result...

Parent button reference is System.Windows.Controls.Button

Child button reference is null!


回答1:


The short answer to a long question is that Microsoft doesn't expect you to derive from FrameworkElement without doing a little plumbing.

Just doing derivation, breaks the logical tree which is used when doing binding by element name.

You probably also have to plum up the visual tree, and overload the arrange/measure parts of framework element. (We don't do that here as we aren't visual in the example.)

In this specific case we need to add any children of your object to the logical tree or break the ability to bind child elements.

A good example of someone who solved this is here

Information on overriding the logical tree is here

Anyways, the code needed to fix this SIMPLE example only relied on the logical tree (as the child object isn't really visual.)

Adding this function and changing the dependency property makes the binding work.

        private static readonly DependencyProperty ChildElementProperty =
                    DependencyProperty.Register("ChildElement",
                    typeof(MyChildElement),
                    typeof(MyFrameworkElement),
                    new PropertyMetadata(OnChildElementChanged));

    private static void OnChildElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyFrameworkElement control = d as MyFrameworkElement;

        if (e.OldValue != null)
        {
            control.RemoveLogicalChild(e.OldValue);
        }

        control.AddLogicalChild(e.NewValue);
    }



回答2:


First, when you setup the xaml like this:

<my:MyFrameworkElement x:Name="ParentName" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ButtonReferenceInParent="{Binding ElementName=buttonisme}"/>
<my:MyChildElement x:Name="ChildName" ButtonReferenceInChild="{Binding ElementName=buttonisme}"/>

It works. I did this because I suspect a visual tree upwards traversal search for the Element Name you use in the binding.

I am still figuring out how the binding can be succesfull in your nested scenario. But maybe this may give you some hint...



来源:https://stackoverflow.com/questions/12671053/why-does-binding-fail-when-binding-a-child-element-to-another-element-when-the-p

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!