C# 数据绑定到UserControl内部的UserControl

C# 数据绑定到UserControl内部的UserControl,c#,wpf,xaml,data-binding,user-controls,C#,Wpf,Xaml,Data Binding,User Controls,在我的项目中,我需要将数据绑定到驻留在另一个UserControl中的UserControl。为了简洁起见,我创建了一个概念相似但非常简单的项目 假设我正在创建一个电话簿应用程序,其中包含两个用户控件,如下所示 窗口中的蓝色大框是一个UserControl,显示所有者的姓名(Jane Doe),其中的每个黄色框也是UserControl,显示联系人的姓名和电话号码 我有两个类保存相关数据,如下所示: public class Person { public string Name {

在我的项目中,我需要将数据绑定到驻留在另一个UserControl中的UserControl。为了简洁起见,我创建了一个概念相似但非常简单的项目

假设我正在创建一个电话簿应用程序,其中包含两个用户控件,如下所示

窗口中的蓝色大框是一个UserControl,显示所有者的姓名(Jane Doe),其中的每个黄色框也是UserControl,显示联系人的姓名和电话号码

我有两个类保存相关数据,如下所示:

public class Person
{
    public string Name { get; set; }
    public string Phone { get; set; }
    public Person() { }
}

public class PhoneBook
{
    public string OwnerName { get; set; }
    public ObservableCollection<Person> ContactList { get; set; }
    public PhoneBook() { }
}
PhoneBookData
是ViewModel上的
PhoneBook
类的一个实例

我的两个用户控件,以及它们的
依赖属性
如下所示

UCPhoneBook用户控件(蓝色框):

<UserControl x:Class="UserControlDataBinding.UCPerson"
             d:DesignHeight="26" d:DesignWidth="400">
    <Canvas x:Name="ucCanvasPerson" Background="WhiteSmoke">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Name="lblName" 
                   HorizontalAlignment="Left" VerticalAlignment="Center"
                   Content="{Binding Name}"></Label>
            <Label Grid.Column="2" Name="lblPhone" 
                   HorizontalAlignment="Right" VerticalAlignment="Center"
                   Content="{Binding Phone}"></Label>
        </Grid>
    </Canvas>
</UserControl>
在这里,我使用
ItemsControl
动态绑定
UCPerson
UserControls,以便在运行时添加任意数量的控件

<UserControl x:Class="UserControlDataBinding.UCPhoneBook"
             d:DesignHeight="300" d:DesignWidth="450">
    <Canvas x:Name="ucCanvasPhoneBook" Background="White">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <GroupBox Grid.Row="0" Header="Phonebook">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Label Grid.Row="0" Name="lblOwnerName" 
                           Content="{Binding Path=MainPhoneBook.OwnerName}">
                    </Label>
                </Grid>
            </GroupBox>

            <ItemsControl Grid.Row="1"
                          ItemsSource="{Binding PhoneBookData.ContactList}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:Person}">
                        <local:UCPerson PersonData="{Binding Person}"></local:UCPerson>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Vertical"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>
    </Canvas>
</UserControl>
UCPerson用户控件(黄色框):

<UserControl x:Class="UserControlDataBinding.UCPerson"
             d:DesignHeight="26" d:DesignWidth="400">
    <Canvas x:Name="ucCanvasPerson" Background="WhiteSmoke">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Name="lblName" 
                   HorizontalAlignment="Left" VerticalAlignment="Center"
                   Content="{Binding Name}"></Label>
            <Label Grid.Column="2" Name="lblPhone" 
                   HorizontalAlignment="Right" VerticalAlignment="Center"
                   Content="{Binding Phone}"></Label>
        </Grid>
    </Canvas>
</UserControl>
当我运行它时,我可以在第一个UserControl(蓝色框)的顶部看到所有者的名字。但是,它似乎没有正确地绑定其中的
UCPerson
用户控件,我得到一个空列表,如下所示:

我的猜测是,我没有正确绑定到第一个UserControl中的
ItemsControl
。我对数据绑定相当陌生,似乎不知道正确的方法是什么


我做错了什么?

这一切都可以大大简化


首先,去掉
UserControl
s中的所有
Canvas
Canvas
es将导致所有内容重叠。仅当您想要任意定位子对象并且可能重叠时,才使用
画布。WPF布局通常使用“流”和相对定位。标准布局父级是
StackPanel
Grid
WrapPanel
,以及偶尔出现的
UniformGrid
。对于
项目控件
,您可以省略
项目模板
,因为默认设置已经是一个垂直方向的
堆栈面板

。@这是数据上下文。@EdPlunkett,谢谢,这似乎行得通!我遵循这个()示例,并尝试在这里和那里进行编辑。所以基本上我不需要依赖属性来做这个?很遗憾,你选择的模型并不理想。公平地说,它已经六岁了。
LayoutRoot.DataContext=this东西比应该受到谴责的
DataContext=this要好得多(我想有些人误以为你在这么做),但现在这仍然不是一个好的做法。@Sach向UC提供他们的viewmodels非常有效,正如我上面所说明的,但在某些情况下,你可能还想添加一个或两个依赖性属性,仅用于纯视觉的内容:例如,父视图可能希望传入一些笔刷或样式以应用于UC的一部分。因此,您可以为这些内容编写dependnecy属性,并在UC XAML中进行绑定,如
{Binding BlahStyleProp,RelativeSource={RelativeSource AncestorType=UserControl}
。UCs上的DPs并不是一件坏事——只是对于你所做的事情来说并不必要。@Sach我知道了!是画布!扔掉所有的画布。他们对布局做了一些奇怪的事情,这不仅仅是一个中立的面板控件。威尔,我有点困惑,因为这是我来这里时正在关注的文章。我想我需要回去从头开始学习数据绑定。@Will,谢谢!我去看看。你们帮了大忙。@EdPlunkett啊,糟了,你们说得对。删除令人困惑的评论是为了防止混淆,而不是出于尴尬,小指骂人。@会有哪些令人困惑的评论?我什么也没看见。
<UserControl x:Class="UserControlDataBinding.UCPerson"
             d:DesignHeight="26" d:DesignWidth="400">
    <Canvas x:Name="ucCanvasPerson" Background="WhiteSmoke">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Name="lblName" 
                   HorizontalAlignment="Left" VerticalAlignment="Center"
                   Content="{Binding Name}"></Label>
            <Label Grid.Column="2" Name="lblPhone" 
                   HorizontalAlignment="Right" VerticalAlignment="Center"
                   Content="{Binding Phone}"></Label>
        </Grid>
    </Canvas>
</UserControl>
public partial class UCPerson : UserControl
{
    private static readonly DependencyProperty PersonProperty = DependencyProperty.Register("PersonData", typeof(Person), typeof(UCPerson), new PropertyMetadata(null));
    public Person PersonData
    {
        get { return (Person)GetValue(PersonProperty); }
        set { SetValue(PersonProperty, value); }
    }

    public UCPerson()
    {
        InitializeComponent();
        ucCanvasPerson.DataContext = this;
    }
}