2

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?

3
  • Using x:Bind binds to the Framework element (code-behind class) and it needs to have all types fixed at compile time. Why even use x:Bind in this case? Commented Oct 11, 2019 at 13:39
  • @Çöđěxěŕ: Why? Compile-time safety for example. Commented Oct 11, 2019 at 13:43
  • @mm8 good point as the user is already seeing... Commented Oct 11, 2019 at 13:44

3 Answers 3

6

I'd suggest create Dependency Property for ProjectItem on your MyUserControl1.xaml.cs

  public static readonly DependencyProperty ProjectItemProperty =
        DependencyProperty.Register(
            nameof(ProjectItem),
            typeof(ProjectItem),
            typeof(MyUserControl1),
            null);

    public ProjectItem ProjectItem
    {
        get => (ProjectItem)GetValue(ProjectItemProperty);
        set => SetValue(ProjectItemProperty, value);
    }

Then on your XAML, bind the properties of your ProjectItem Dependency Property:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="{x:Bind ProjectItem.Name, Mode=OneWay}" />
    <TextBlock Text="{x:Bind ProjectItem.Description, Mode=OneWay}" />
</StackPanel>

Then on your MainPage.xaml, pass on the 'ProjectItem' collection item.

<DataTemplate x:DataType="local:ProjectItem">
            <local:MyUserControl1 ProjectItem="{x:Bind}"/>
        </DataTemplate>
Sign up to request clarification or add additional context in comments.

1 Comment

What if ProjectItem has 10 Properties? then you need to create 10 Dependancy properties. So instead we can try and create one Dependancy Property as ProjectItem? Just a suggestion.
3

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.

Comments

2

This could be faster as the DataContext is casted only once when the Control is Loaded.

public ProjectItem ProjectItem { get; private set; }

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

Add this if DataContext change in MainPage:

    DataContextChanged += (s, e) => 
    {
        ProjectItem = (ProjectItem)DataContext;
        Bindings.Update();
    };

Based on the answer given by @mm8.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.