绑定到UserControl内部的UserControl [英] DataBinding to a UserControl inside of a UserControl

查看:67
本文介绍了绑定到UserControl内部的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 UserControls. Canvas isn't just a neutral panel/container control. The Canvases 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 ItemsControlis 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆