Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataBinding to a UserControl inside of a UserControl [duplicate]

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.

enter image description here

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() { }
}

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 is an instance of PhoneBook class on the ViewModel.

My two user controls, and their DependancyProperties look like below.

UCPhoneBook UserControl (the blue box):

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>

Its 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 (the yellow boxes):

<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>

Its 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;
    }
}

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:

enter image description here

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.

What am I doing wrong here?

like image 499
Sach Avatar asked Jan 27 '26 15:01

Sach


1 Answers

This can all be greatly simplified.

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.

like image 89
15ee8f99-57ff-4f92-890c-b56153 Avatar answered Jan 29 '26 03:01

15ee8f99-57ff-4f92-890c-b56153



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!