Search code examples
c#xamluwpwin-universal-app

x:Bind and UserControls


I'm trying to use compiled bindings in UWP with a simple use case.

In order to make my XAML more readable easy to manage, I've extracted the XAML of a DataTemplate to a UserControl. So I transformed this

MainPage.xaml

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <ListView ItemsSource="{x:Bind ViewModel.Items}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:ProjectItem">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{x:Bind Name, Mode=OneWay}" />
                    <TextBlock Text="{x:Bind Description, Mode=OneWay}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

Into this

MainPage.xaml

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <ListView ItemsSource="{x:Bind ViewModel.Items}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:ProjectItem">
                <local:MyUserControl1 />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

MyUserControl1.xaml

<UserControl
    x:Class="App1.MyUserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{x:Bind Name}" />
        <TextBlock Text="{x:Bind Description}" />
    </StackPanel>
</UserControl>

The problem is that it doesn't even compile because x:Bind doesn't know the context.

How does x:Bind cover this use case?


Solution

  • If you use this approach, you could (or rather need to) add a property to MyUserControl1.xaml.cs that casts the current DataContext to a ProjectItem and returns it:

    public ProjectItem Item => DataContext as ProjectItem;
    
    public MyUserControl1()
    {
        InitializeComponent();
        DataContextChanged += (s, e) => Bindings.Update();
    }
    

    You then bind to this property in the XAML markup:

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{x:Bind Item.Name}" />
        <TextBlock Text="{x:Bind Item.Description}" />
    </StackPanel>
    

    The other option would to use non-compiled {Bindings} or get rid of MyUserControl1 and revert to the inline DataTemplate.