Путаница привязки WPF: составной DependencyObject

У меня есть состав класса DependencyObject, который выглядит следующим образом:

public class A : DependencyObject {
    public AB AB { get { ... } set { ... } }
    public AB AC { get { ... } set { ... } }
}

public class AB : DependencyObject {
    public string Property1 { get { ... } set { ... } }
    public string Property2 { get { ... } set { ... } }
    public string Property3 { get { ... } set { ... } }
}

public class AC : DependencyObject {
    public string Property1 { get { ... } set { ... } }
    public string Property2 { get { ... } set { ... } }
}

На A, AB и AC все свойства выполняют типичные операции GetValue и SetValue, ссылаясь на обычные статические свойства.

Теперь классы A, AB и AC имеют соответствующие пользовательские элементы управления AGroupBox, ABGrid, ACGrid. AGroupBox имеет корневое свойство класса A, ABGrid имеет корневое свойство класса AB, а ACGrid имеет корневое свойство класса AC.

И ABGrid, и ACGrid имеют рабочие привязки (например, ABGrid Содержит элемент управления TextBox, свойство Text которого в двух направлениях привязано к свойству AB1). Я проверил это, создав простое Window и сделав ABGrid единственным дочерним элементом Content для Window и в коде настройки ABGrid.AB = новый AB(); тот же сценарий для ACGrid.AC = новый AC();.

Проблема в том, когда я пытаюсь сделать то же самое с AGroupBox. Я пытаюсь добавить AGroupBox в качестве единственного дочернего элемента содержимого Window в XAML и установить для свойства AGroupBox.A значение new A() {AB = new AB(), AC = new AC()}; и привязка элементов управления не удается. AB и AC имеют значения по умолчанию для своих свойств PropertyN.

Есть идеи о том, что мне не хватает? Есть ли другой маршрут, по которому я должен идти?

РЕДАКТИРОВАТЬ: Дополнительный комментарий - если я добавлю строковое свойство к A, (String1) и привяжу его к текстовой части GroupBox, тогда будет работать привязка к этому свойству, но не к AC и AB свойству A.

РЕДАКТИРОВАТЬ-2: По запросу Дэвида Хэя (весь код находится в пространстве имен wpfStackru):

A.cs

public class A : DependencyObject {
    static public DependencyProperty BProperty { get; private set; }
    static public DependencyProperty CProperty { get; private set; }
    static public DependencyProperty PropertyProperty { get; private set; }

    static A() {
        BProperty = DependencyProperty.Register("B", typeof(B), typeof(A));
        CProperty = DependencyProperty.Register("C", typeof(C), typeof(A));
        PropertyProperty = DependencyProperty.Register("Property", typeof(string), typeof(A));
    }

    public B B {
        get { return (B)GetValue(BProperty); }
        set { SetValue(BProperty, value); }
    }

    public C C {
        get { return (C)GetValue(CProperty); }
        set { SetValue(CProperty, value); }
    }

    public string Property {
        get { return (string)GetValue(PropertyProperty); }
        set { SetValue(PropertyProperty, value); }
    }

    public A() {
        Property = "A's Default Value";
        B = new B();
        C = new C();
    }
}

b.cs

public class B : DependencyObject {
    static public DependencyProperty PropertyProperty { get; private set; }

    static B() {
        PropertyProperty = DependencyProperty.Register("Property", typeof(string), typeof(B));
    }

    public string Property {
        get { return (string)GetValue(PropertyProperty); }
        set { SetValue(PropertyProperty, value); }
    }

    public B() {
        Property = "B's Default Value";
    }
}

C.cs

public class C : DependencyObject {
    static public DependencyProperty PropertyProperty { get; private set; }

    static C() {
        PropertyProperty = DependencyProperty.Register("Property", typeof(string), typeof(C));
    }

    public string Property {
        get { return (string)GetValue(PropertyProperty); }
        set { SetValue(PropertyProperty, value); }
    }

    public C() {
        Property = "C's Default Value";
    }
}

AGroupBox.xaml

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:wpfStackru"
    x:Class="wpfStackru.AGroupBox"
    DataContext="{Binding RelativeSource={RelativeSource Self}, Path=A}"
    Width="300"
    Height="72"
    >
    <GroupBox Header="{Binding Property}">
        <StackPanel >
            <local:BGrid B="{Binding B}"/>
            <local:CGrid C="{Binding C}"/>
        </StackPanel>
    </GroupBox>
</UserControl>

AGroupBox.xaml.cs

public partial class AGroupBox : UserControl {
    static public DependencyProperty AProperty { get; private set; }

    static AGroupBox() {
        AProperty = DependencyProperty.Register("A", typeof(A), typeof(AGroupBox));
    }

    public A A {
        get { return (A)GetValue(AProperty); }
        set { SetValue(AProperty, value); }
    }

    public AGroupBox() {
        InitializeComponent();
    }
}

BGrid.xaml

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="wpfStackru.BGrid"
    DataContext="{Binding RelativeSource={RelativeSource Self}, Path=B}"
    >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Content="Property"/>
        <TextBox Grid.Column="1" Text="{Binding Property}"/>
    </Grid>
</UserControl>

BGrid.xaml.cs

public partial class BGrid : UserControl {
    static public DependencyProperty BProperty { get; private set; }

    static BGrid() {
        BProperty = DependencyProperty.Register("B", typeof(B), typeof(BGrid));
    }

    public B B {
        get { return (B)GetValue(BProperty); }
        set { SetValue(BProperty, value); }
    }

    public BGrid() {
        InitializeComponent();
    }
}

CGrid.xaml

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="wpfStackru.CGrid"
    DataContext="{Binding RelativeSource={RelativeSource Self}, Path=C}"
    >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Content="Property"/>
        <TextBox Grid.Column="1" Text="{Binding Property}"/>
    </Grid>
</UserControl>

CGrid.xaml.cs

public partial class CGrid : UserControl {
    static public DependencyProperty CProperty { get; private set; }

    static CGrid() {
        CProperty = DependencyProperty.Register("C", typeof(C), typeof(CGrid));
    }

    public C C {
        get { return (C)GetValue(CProperty); }
        set { SetValue(CProperty, value); }
    }

    public CGrid() {
        InitializeComponent();
    }
}

Window1.xaml

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:wpfStackru"
    x:Class="wpfStackru.Window1"
    Width="400"
    Height="200"
>
    <local:AGroupBox x:Name="aGroupBox" />
</Window>

Window1.xaml.cs

public partial class Window1 : Window {
    public Window1() {
        InitializeComponent();

        aGroupBox.A = new A()
        {
            Property = "A's Custom Property Value",
            B = new B()
            {
                Property = "B's Custom Property Value"
            },
            C = new C()
            {
                Property = "C's Custom Property Value"
            }
        };
    }
}

1 ответ

Решение

Попробуйте подставить в AGroupBox.xaml следующее

<local:BGrid B="{Binding Path=A.B, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:AGroupBox}}}"/>
<local:CGrid C="{Binding Path=A.C, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:AGroupBox}}}"/>

Он не разрешал текст данных должным образом для этих двух строк, и поэтому не искал нужного места для B и C.

Другие вопросы по тегам