Search code examples
c#uwpuwp-xamlxaml-binding

UWP XAML and C# - x:Bind on a DataTemplate inside a ResourceDictionary


Context: I'm writing a UWP Twitter client. One of the properties of my Tweet class is a bool called IsRetweet - if the tweet contains a retweet, this is set to True.

I want to use this with x:Load in order to conditionally load an extra row in my UI that displays "@username retweeted".

I'm going off this example: https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-load-attribute

And here's my XAML, which is inside a ResourceDictionary:

<Grid Grid.Row="0" x:Name="RetweetedBy"  x:Load="{x:Bind (x:Boolean)IsRetweet, Converter={StaticResource DebugThis}}">
    <StackPanel Orientation="Horizontal" Padding="4 8 4 0">
        <StackPanel.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="12"/>
                <Setter Property="Foreground" Value="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
            </Style>
        </StackPanel.Resources>
        <Border Height="28">
            <TextBlock Height="24" FontFamily="{StaticResource FontAwesome}" xml:space="preserve"><Run Text="&#xf079;&#160;"/></TextBlock>
        </Border>
        <TextBlock Text="{Binding Path=User.Name}" />
        <TextBlock Text=" retweeted"/>
    </StackPanel>
</Grid>

I added a temporary converter called DebugThis to the field I'm binding for x:Load, which looks like this:

public class DebugThis : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        bool IsRetweet = (bool)value;

        return IsRetweet;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

I stuck a breakpoint on this, and I'm not even hitting the converter, so I'm guessing something is wrong with my XAML binding. I've triple-checked the objects that use this DataTemplate, and each object definitely has the IsRetweet property set correctly.

ETA: I'm able to get x:Bind to load bound data by adding this to my UI page's XAML:

<Page.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <tweeter:Visuals />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Page.Resources>

However, now if I load new content into the UI dynamically, x:Bind bindings aren't rendering.

Example: enter image description here


Solution

  • Your App.xaml is only merging in the XAML part of your ResourceDictionary, as that is all you have asked it to do.

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Visuals.xaml"/> <!-- Only loads XAML -->
    </ResourceDictionary.MergedDictionaries>
    

    However, as you are using x:Bind / x:Load in your DataTemplates there's compiler generated code being created for your class, and this code will never get loaded because you are loading your ResourceDictionary as loose XAML rather than a class.

    To load the ResourceDictionary with it's associated compiler-generated code for x:Load/x:Bind / as a full class, replace the above in App.xaml with:

    <ResourceDictionary.MergedDictionaries>
        <local:Visuals />
    </ResourceDictionary.MergedDictionaries>
    

    (At which point <Grid Grid.Row="0" x:Name="RetweetedBy" x:Load="{x:Bind IsRetweet}"> is sufficient to get it to work as you need.)