2

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

CXL
  • 1,094
  • 2
  • 15
  • 38
  • You shouldn't need the x:Boolean cast in there if you've set x:DataType on the DataTemplate (which you absolutely need to for this to work). Otherwise this looks fine without a larger sample - preferably the entire DataTemplate tag? (Fwiw, for some reason x:Load can actually hamper performance in DataTemplates, for reasons I've yet to work out) (And as an aside... It's not the best idea to have each instance of a datatemplate declare Thier own styles - you may as well do it once and save them being created again and again) – Johnny Westlake Jul 31 '18 at 20:14
  • My entire project is public here: https://github.com/TweeterUWP/Tweeter My DataTemplate is inside a ResourceDictionary, with my DataType set to the object that uses the DataTemplate (Tweeter.Tweet2). I ended up using the Setter inside the StackPanel because I couldn't get the Setter at the page level to apply to the StackPanel in question, although that might just be me being a retard... – CXL Jul 31 '18 at 20:54
  • I can only say that with the code on GitHub, clicking on a Tweet opens that tweet in a new blade with the x:Load properly applied in the new blade :/ [See example](https://i.imgur.com/RJWLcCh.png). Also, you want to do that merging in App.xaml, replace your *current* ResourceDictionary merging in App.xaml- don't do it on the page itself. Doing in on the page is likely the root of your new problem (there are now conflicting ResourceDictionaries - one of which is technically broken) - see my answer below. – Johnny Westlake Jul 31 '18 at 22:24
  • I think I might have not pushed my last changes using x:Load in the binding for the tweet text. Moving my MergedDictionaries section to App.xaml fixed this, though. – CXL Aug 01 '18 at 15:35

1 Answers1

4

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.)

Johnny Westlake
  • 1,461
  • 10
  • 13
  • That worked! What's the difference? I'm guessing it's that the app-level was stomping over the page-level inclusion of the ResourceDictionary? – CXL Jul 31 '18 at 23:02