DataBinding 到 UserControl 内部的 UserControl
DataBinding to a UserControl inside of a UserControl
在我的项目中,我需要将数据绑定到驻留在另一个 UserControl 中的 UserControl。为了简洁起见,我创建了一个概念相似但非常简单的项目。
假设我正在创建一个 Phone 图书应用程序,其中有两个用户控件,如下所示。
window 中的蓝色大框是一个 UserControl,它显示所有者的姓名 (Jane Doe),其中的每个黄色框也是 UserControl,显示联系人姓名和 phone个数。
我有两个class持有相关资料,如下:
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() { }
}
在我的 MainWindow
中,我使用 ViewModel 并像这样绑定到 PhoneBook
UserControl:
<Window x:Class="UserControlDataBinding.MainWindow"
Title="MainWindow" Height="300" Width="350"
DataContext="{Binding Source={StaticResource mainViewModelLocator},Path=ViewModelPhoneBook}">
<Grid>
<local:UCPhoneBook x:Name="ucPhoneBook" MainPhoneBook="{Binding PhoneBookData}"></local:UCPhoneBook>
</Grid>
</Window>
PhoneBookData
是 ViewModel 上 PhoneBook
class 的一个实例。
我的两个用户控件,它们的 DependancyProperties
如下所示。
UCPhoneBook UserControl(蓝框):
我在这里使用 ItemsControl
动态绑定 UCPerson
用户控件,这样我就可以在 运行 时间内添加任意数量的用户控件。
<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>
是DependancyProperty
:
public partial class UCPhoneBook : UserControl
{
private static readonly DependencyProperty PhoneBookProperty = DependencyProperty.Register("MainPhoneBook", typeof(PhoneBook), typeof(UCPhoneBook), new PropertyMetadata(null));
public PhoneBook MainPhoneBook
{
get { return (PhoneBook)GetValue(PhoneBookProperty); }
set { SetValue(PhoneBookProperty, value); }
}
public UCPhoneBook()
{
InitializeComponent();
ucCanvasPhoneBook.DataContext = this;
}
}
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>
是DependancyProperty
:
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;
}
}
当我 运行 执行此操作时,我可以在第一个 UserControl(蓝色框)的顶部看到所有者的名称就好了。但是,它似乎没有正确绑定其中的 UCPerson
用户控件,我得到一个空列表,如下所示:
我的猜测是我没有正确绑定到第一个 UserControl 中的 ItemsControl
。我是 DataBinding 的新手,似乎无法弄清楚正确的方法是什么。
我做错了什么?
这一切都可以大大简化。
首先,删除 UserControl
中的所有 Canvas
。 Canvas isn't just a neutral panel/container control。 Canvas
es 将导致一切都被叠加。仅当您想任意放置子项并可能叠加时才使用 Canvas
。 WPF 布局通常使用“流”和相对定位。标准布局父级为 StackPanel
、Grid
、WrapPanel
,偶尔也有 UniformGrid
。您可以省略 ItemsControl
的 ItemsPanelTemplate
,因为默认值已经是垂直方向的 StackPanel
.
在我的项目中,我需要将数据绑定到驻留在另一个 UserControl 中的 UserControl。为了简洁起见,我创建了一个概念相似但非常简单的项目。
假设我正在创建一个 Phone 图书应用程序,其中有两个用户控件,如下所示。
window 中的蓝色大框是一个 UserControl,它显示所有者的姓名 (Jane Doe),其中的每个黄色框也是 UserControl,显示联系人姓名和 phone个数。
我有两个class持有相关资料,如下:
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() { }
}
在我的 MainWindow
中,我使用 ViewModel 并像这样绑定到 PhoneBook
UserControl:
<Window x:Class="UserControlDataBinding.MainWindow"
Title="MainWindow" Height="300" Width="350"
DataContext="{Binding Source={StaticResource mainViewModelLocator},Path=ViewModelPhoneBook}">
<Grid>
<local:UCPhoneBook x:Name="ucPhoneBook" MainPhoneBook="{Binding PhoneBookData}"></local:UCPhoneBook>
</Grid>
</Window>
PhoneBookData
是 ViewModel 上 PhoneBook
class 的一个实例。
我的两个用户控件,它们的 DependancyProperties
如下所示。
UCPhoneBook UserControl(蓝框):
我在这里使用 ItemsControl
动态绑定 UCPerson
用户控件,这样我就可以在 运行 时间内添加任意数量的用户控件。
<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>
是DependancyProperty
:
public partial class UCPhoneBook : UserControl
{
private static readonly DependencyProperty PhoneBookProperty = DependencyProperty.Register("MainPhoneBook", typeof(PhoneBook), typeof(UCPhoneBook), new PropertyMetadata(null));
public PhoneBook MainPhoneBook
{
get { return (PhoneBook)GetValue(PhoneBookProperty); }
set { SetValue(PhoneBookProperty, value); }
}
public UCPhoneBook()
{
InitializeComponent();
ucCanvasPhoneBook.DataContext = this;
}
}
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>
是DependancyProperty
:
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;
}
}
当我 运行 执行此操作时,我可以在第一个 UserControl(蓝色框)的顶部看到所有者的名称就好了。但是,它似乎没有正确绑定其中的 UCPerson
用户控件,我得到一个空列表,如下所示:
我的猜测是我没有正确绑定到第一个 UserControl 中的 ItemsControl
。我是 DataBinding 的新手,似乎无法弄清楚正确的方法是什么。
我做错了什么?
这一切都可以大大简化。
首先,删除 UserControl
中的所有 Canvas
。 Canvas isn't just a neutral panel/container control。 Canvas
es 将导致一切都被叠加。仅当您想任意放置子项并可能叠加时才使用 Canvas
。 WPF 布局通常使用“流”和相对定位。标准布局父级为 StackPanel
、Grid
、WrapPanel
,偶尔也有 UniformGrid
。您可以省略 ItemsControl
的 ItemsPanelTemplate
,因为默认值已经是垂直方向的 StackPanel
.