Путаница привязки 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.