【问题标题】:WPF Binding Confusion: Composite DependencyObjectWPF 绑定混淆:复合 DependencyObject
【发布时间】:2010-12-24 01:48:29
【问题描述】:

我有一个 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 类都有对应的 UserControls AGroupBox、ABGrid、ACGrid。 AGroupBox 有一个根 A 类属性,ABGrid 有一个根 AB 类属性,ACGrid 有一个根 AC 类属性。

ABGrid 和 ACGrid 都有有效的绑定(例如,ABGrid 包含一个 TextBox 控件,其 Text 属性双向绑定到 AB 的 Property1。)我已经通过创建一个简单的 Window 并将 ABGrid 作为 Window 的唯一 Content 子项和在设置 ABGrid.AB = new AB(); 背后的代码ACGrid.AC = new AC(); 的情况相同。

问题是当我尝试对 AGroupBox 进行类似操作时。我尝试将 AGroupBox 添加为 XAML 中 Window 内容的单个子项,并将 AGroupBox.A 属性设置为 new A() {AB = new AB(), AC = new AC()};并且控件的绑定失败。 AB 和 AC 的 PropertyN 属性具有默认值。

对我缺少什么有任何见解吗?我应该采取不同的路线吗?

编辑:附加注释-如果我将字符串属性添加到 A, (String1) 并将其绑定到 GroupBox 的文本部分,则绑定到该属性有效,但不绑定到 A 的 AC 和 AB 属性。

EDIT-2:根据 David Hay 的要求(所有代码都在命名空间 wpfStackOverflow 中):

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:wpfStackOverflow"
    x:Class="wpfStackOverflow.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="wpfStackOverflow.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="wpfStackOverflow.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:wpfStackOverflow"
    x:Class="wpfStackOverflow.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"
            }
        };
    }
}

【问题讨论】:

  • 我们将不得不查看 AGroupBox 的 XAML——特别是绑定声明——以便在这里提供帮助。我的猜测是您的绑定语句未正确设置以访问适当的数据。另外,调试输出中绑定失败消息的读数是什么?

标签: c# user-controls binding dependencyobject


【解决方案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。

【讨论】:

  • 感谢您的帮助!我在 Visual Studio 的输出窗口中查看了调试输出,没有任何绑定警告,您是如何确定问题的?对不那么冗长的解决方案有任何想法吗?
  • 这是一篇关于绑定调试技术的好文章的链接:beacosta.com/blog/?p=52 我知道有一种更简洁的方法可以做到这一点(类似于您最初的尝试),但我不能现在就在脑海中想象出来。
猜你喜欢
  • 1970-01-01
  • 2016-08-02
  • 2013-06-07
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多