绑定到UserControl内部的UserControl [英] DataBinding to a UserControl inside of a UserControl
问题描述
在我的项目中,我需要将DataBind绑定到另一个用户控件中的一个用户控件。为了简洁起见,我创建了一个概念上相似但非常简单的项目。
In my project, I need to DataBind to a UserControl that resides in another UserControl. For the sake of brevity, I created a conceptually similar but very simple project.
想象一下,我正在创建一个电话簿应用程序,其中有两个用户控件,看起来如下所示。
Imagine that I am creating a Phone Book application, with two user controls in it, that looks like below.
该窗口将是一个UserControl,它显示所有者的姓名(简·多伊),其中每个黄色框也是UserControl,它显示联系人的姓名和电话号码。
The large blue box in the window would be one UserControl, which displays the owner's name (Jane Doe), and each of the yellow boxes within it are also UserControls, which display contacts' names and phone numbers.
我拥有两个持有相关数据的类,如下所示:
I have two classes that I hold related data, as follows:
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,如下所示:
In my MainWindow
, I use a ViewModel and bind to the PhoneBook
UserControl like so:
<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
是<$ c的实例$ c> PhoneBook 类。
我的两个用户控件及其 DependencyProperties
如下所示。
My two user controls, and their DependancyProperties
look like below.
UCPhoneBook UserControl(蓝色框):
这里我使用 ItemsControl
动态绑定 UCPerson
UserControls,因此我可以在其中添加任意数量的
Here I'm using an ItemsControl
to dynamically bind the UCPerson
UserControls so I can add as many as I like in runtime.
<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>
其 DependencyProperty
:
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(黄色框):
<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>
其 DependencyProperty
:
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
用户控件,并且我得到一个空列表,如下所示:
When I run this, I can see the Owner's Name at the top of the first UserControl (blue box) just fine. However, it doesn't seem to correctly bind the UCPerson
user controls within, and I get an empty list like so:
我的猜测是我没有正确绑定到 ItemsControl
在第一个UserControl中。我对DataBinding很陌生,似乎无法弄清楚正确的方法是什么。
My guess is that I'm not correctly binding to the ItemsControl
inside the first UserControl. I'm pretty new to DataBinding and can't seem to figure out what the correct approach is.
我在这里做错什么了?
推荐答案
这一切都可以大大简化。
This can all be greatly simplified.
首先,清除 UserControl
Canvas > s。 画布不只是中性面板/容器控件。 Canvas
es将导致所有内容叠加。仅当要随意放置并可能重叠放置子项时,才使用 Canvas
。 WPF布局通常使用流和相对位置。标准布局父级为 StackPanel
, Grid
, WrapPanel
,以及偶尔的 UniformGrid
。您可以为 ItemsControl
省略 ItemsPanelTemplate
,因为默认值已经是垂直方向的 StackPanel
。
First, get rid of every Canvas
in your UserControl
s. Canvas isn't just a neutral panel/container control. The Canvas
es will cause everything to be superimposed. Only use a Canvas
when you want to position children arbitrarily, and potentially superimposed. WPF layout usually uses "flow" and relative positioning. The standard layout parents are StackPanel
, Grid
, WrapPanel
, and the occasional UniformGrid
. You can omit the ItemsPanelTemplate
for the ItemsControl
, since the default is already a vertically-oriented StackPanel
.
首次修复UCPerson.xaml.cs:
First fix UCPerson.xaml.cs:
public partial class UCPerson : UserControl
{
public UCPerson()
{
InitializeComponent();
}
}
然后修复数据模板:
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:UCPerson />
</DataTemplate>
</ItemsControl.ItemTemplate>
<$ c $的 DataContext
c> UserControl 应该是它显示的视图模型。 ItemsControl
中的每个项目都是 Person
。在 ItemsControl
的 ItemTemplate
中, DataContext
是item-一个人员
。 DataTemplate
中的 UserControl
将继承该 DataContext
。
The DataContext
of a UserControl
should be the viewmodel that it displays. Each item in the ItemsControl
is a Person
. In the ItemTemplate
for the ItemsControl
, the DataContext
is the item -- a Person
. The UserControl
in the DataTemplate
will inherit that DataContext
.
无需设置 DataTemplate
的 DataType
。这里没有用。
No need to set the DataType
of the DataTemplate
. That's not used here.
当我们在这里时,其他用户控件也会从相同的处理中受益:
While we're here, the other user control would benefit from the same treatment:
public partial class UCPhoneBook : UserControl
{
public UCPhoneBook()
{
InitializeComponent();
}
}
XAML(部分)
<Label Grid.Row="0" Name="lblOwnerName"
Content="{Binding OwnerName}">
</Label>
</Grid>
</GroupBox>
<ItemsControl Grid.Row="1"
ItemsSource="{Binding ContactList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:UCPerson />
</DataTemplate>
</ItemsControl.ItemTemplate>
MainWindow.xaml
MainWindow.xaml
<Window x:Class="UserControlDataBinding.MainWindow"
Title="MainWindow" Height="300" Width="350"
DataContext="{Binding Source={StaticResource mainViewModelLocator},Path=ViewModelPhoneBook}">
<Grid>
<local:UCPhoneBook DataContext="{Binding PhoneBookData}" />
</Grid>
</Window>
顺便说一句,您在哪里得到关于同一个物业拥有两个名称的概念?
By the way, where did you get this notion of having two names for the same property?
这篇关于绑定到UserControl内部的UserControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!