【问题标题】:Why does binding fail when binding a child element to another element when the parent succeeds?为什么在父元素成功的情况下将子元素绑定到另一个元素时绑定失败?
【发布时间】:2012-10-01 09:55:29
【问题描述】:

假设我有两个类可以引用第三个 UI 对象(在本例中为按钮)。

另外,父类可以包含子类的一个元素。

如果它们都绑定到同一个控件,以同样的方式,孩子会失败,但父母会成功。

这是 WPF 中的错误吗?


父母:

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

然后是孩子:

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

好的-

现在说我像这样将它们添加到我的 XAML 中:

<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>

当我使用 EXACT 相同的表示法时,为什么绑定在父级上有效但在子级上失败?


这是我的测试代码...

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

这是测试结果...

父按钮引用是 System.Windows.Controls.Button

子按钮引用为空!

【问题讨论】:

    标签: wpf xaml binding visual-tree logical-tree


    【解决方案1】:

    对一个长问题的简短回答是,Microsoft 不希望您从 FrameworkElement 派生而无需做一些调查。

    只是进行推导,破坏了按元素名称进行绑定时使用的逻辑树。

    您可能还必须充实视觉树,并重载框架元素的排列/测量部分。 (我们在这里不这样做,因为我们在示例中不可见。)

    在这种特定情况下,我们需要将对象的任何子对象添加到逻辑树中,或者破坏绑定子元素的能力。

    A good example of someone who solved this is here

    Information on overriding the logical tree is here

    无论如何,修复这个 SIMPLE 示例所需的代码仅依赖于逻辑树(因为子对象不是真正可视的。)

    添加此函数并更改依赖属性使绑定工作。

            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】:

      首先,当您像这样设置 xaml 时:

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

      它有效。我这样做是因为我怀疑您在绑定中使用的元素名称的可视化树向上遍历搜索。

      我仍在研究如何在您的嵌套场景中成功绑定。但也许这会给你一些提示......

      【讨论】:

      • 这种限制会相当......奇怪。我经常绑定处于同一级别的事物(在不同的分支上),例如将属于组的单选按钮绑定到不同子组上的复选框。这可能与孩子不是 UIElement 的事实有关吗?...搞砸这似乎并不能解决它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多