Search code examples
c#xamlwinui-3

WinUI 3 custom control inside another custom control


I can't figure out what's wrong with my code. I create an instance of my own control element - ControlA (created in code). It has a Data property that contains some structure. It displays part of the data and I want to use another custom control - ControlB to display a subset of the data. However, when I set the ControlB component's property with the data from the A component in the xaml, it doesn't appear.

What is wrong?

Create ControlA:

var controlA = new ControlA();
controlA.Data = new Tuple<string, string>("Some text data", "Some subset data");

_grid.Children.Add(controlA);

ControlA:

<?xml version="1.0" encoding="utf-8"?>
<UserControl
    x:Class="winui_3_app.components.ControlA"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:winui_3_app.components"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel>
        <Grid Background="Aquamarine">
            <TextBlock Text="{Binding Data.Item1}" />
        </Grid>
        <Grid Background="Coral">
            <local:ControlB Text="{Binding Data.Item2}" />
        </Grid>
    </StackPanel>
</UserControl>
using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace winui_3_app.components;

public sealed partial class ControlA : UserControl
{
    public Tuple<string, string> Data
    {
        get => (Tuple<string, string>)GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

    public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data), typeof(Tuple<string, string>), typeof(ControlA), new PropertyMetadata(null));

    public ControlA()
    {
        this.InitializeComponent();
        this.DataContext = this;
    }
}

ControlB:

<?xml version="1.0" encoding="utf-8"?>
<UserControl
    x:Class="winui_3_app.components.ControlB"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:winui_3_app.components"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <TextBlock Text="{Binding Text}" />
    </Grid>
</UserControl>
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace winui_3_app.components;

public sealed partial class ControlB : UserControl
{
    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(ControlB), new PropertyMetadata(string.Empty));

    public ControlB()
    {
        this.InitializeComponent();
        this.DataContext = this;
    }
}

Solution

  • So for some reason binding cannot be resolved (maybe someone can add the reason to that) and you get Error: BindingExpression path error: 'Data' property not found on 'CustomInCustom.ControlB'. BindingExpression: Path='Data.Item2' DataItem='CustomInCustom.ControlB'; target element is 'CustomInCustom.ControlB' (Name='null'); target property is 'Text' (type 'String') Even though DataContext of ControlA is already set. Maybe as ControlB gets loaded before ControlA? I am not sure.

    What is important, solution is to replace Binding with x:Bind.