WPF data binding through UserControls

I would like to bind property from the main window's DataContext, above you can see my UserControls and models. So I want to bind the Model.ID.Label1 and Model.ID.Label2 properties to the main_id/card_1/top and main_id/card_1/bottom controls. I hope it's clear. If I enable the ref_lbl Label it will shows the "lbl1", the card_2 still working with the hardcoded texts but the card_1 will be blank. What should I modify to fix the binding on card_1?

I have an ID UserControl and it contains another UserControl.

XAML:

<UserControl x:Class="stack.ID"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:Controls="clr-namespace:stack.Controls"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <Label Name="ref_lbl" Grid.Row="0" Content="{Binding Label1}" Visibility="Collapsed" />
    <Controls:Card x:Name="card_1" Grid.Row="0" TopLabel="{Binding Label1}" BottomLabel="{Binding Label2}" />
    <Controls:Card x:Name="card_2" Grid.Row="1" TopLabel="Text 1" BottomLabel="Text 2" />
</Grid>

Code Behind: default, auto generated

Here is the Card UserControl.

XAML:

<UserControl x:Class="stack.Controls.Card"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <Label Grid.Row="0" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding TopLabel}" />
    <Label Grid.Row="1" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding BottomLabel}" />
</Grid>

Code Behind:

namespace stack.Controls
{
    public partial class Card : UserControl
    {
        public static readonly DependencyProperty TopLabelProperty = DependencyProperty.Register("TopLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
        public static readonly DependencyProperty BottomLabelProperty = DependencyProperty.Register("BottomLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
        public Card()
        {
            InitializeComponent();
        }
        public string TopLabel
        {
            get
            {
                return (string)GetValue(TopLabelProperty);
            }
            set
            {
                SetValue(TopLabelProperty, value);
            }
        }
        public string BottomLabel
        {
            get
            {
                return (string)GetValue(BottomLabelProperty);
            }
            set
            {
                SetValue(BottomLabelProperty, value);
            }
        }
    }
}

And here is my main window.

XAML:

<Window x:Class="stack.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:stack"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <local:Model />
</Window.DataContext>
<Grid>
    <local:ID x:Name="main_id" DataContext="{Binding ID}" />
</Grid>

Code Behind: default, auto generated

And I also have 2 models.

namespace stack
{
    public class IDModel
    {
        private string label1 = "lbl1";
        private string label2 = "lbl2";
        public string Label1
        {
            get
            {
                return label1;
            }
            set
            {
                label1 = value;
            }
        }
        public string Label2
        {
            get
            {
                return label2;
            }
            set
            {
                label2 = value;
            }
        }
    }
    public class Model
    {
        private IDModel id = new IDModel();
        public IDModel ID
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }
    }
}

Upvotes: 0

Views: 67

Answers (1)

Clemens
Clemens

Reputation: 128013

Remove

DataContext="{Binding RelativeSource={RelativeSource Self}}"

from the Card's XAML.

It prevents inheriting the DataContext from its parent ID control, which is necessary when you write

<Controls:Card ... TopLabel="{Binding Label1}" />

Instead write the Content bindings in Card's XAML like this:

<Label ... Content="{Binding TopLabel,
    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />

Upvotes: 1

Related Questions