I’m not entirely sure how to articulate what I’m trying to do, so apologies in advance if anything is unclear.
I’m writing a Twitter client in UWP C#. One of the things I need to do is control the DataTemplate of each tweet in an array of tweets (as returned by Twitter’s API). The problem I’m running into is that I’m going to end up with a lot of identical code, if I make a separate DataTemplate for each tweet type. This is because a tweet can be any of a combination of tweet types (text, image, video, GIF, URL, retweet, and retweet with quote).
Instead of having to copypasta the same DataTemplate for each possible combination, is there a way I can reuse the main Tweet template between different tweet types?
For retweets and quote tweets, the tweet object contains a nested second tweet object (for either the retweet or quote tweet, aka retweet + text), but I don’t know how to pass that second tweet object in any way that would let me reuse my existing template.
Here’s an example of my DataTemplates that I have right now – I’ve only done tweets and retweets so far. RetweetTemplate is almost identical to TweetTemplate, except for one extra row at the top of the grid for the “@username retweeted” text, and the bindings are pointed to Tweet.RetweetedStatus instead of Tweet.
So is there a way I can do this with less redundant code? Or am I stuck making a near-duplicate template for each possible combination to accommodate media and retweeted tweets with media?
<DataTemplate x:Key="TweetTemplate">
<Grid MinHeight="150" Width="450" BorderBrush="{ThemeResource SystemControlDisabledListMediumBrush}" BorderThickness="1" Margin="-12 0" Padding="10 5">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<StackPanel Orientation="Horizontal" Padding="5">
<TextBlock Text="{Binding Path=User.Name}" Margin="0 0 8 0" FontWeight="Bold" />
<TextBlock Text="{Binding Path=User.ScreenName, Converter={StaticResource GetHandle}}" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
<TextBlock Text="⦁" Margin="8 0" />
<TextBlock Text="{Binding CreationDate, Converter={StaticResource FormatDate}}" />
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<TextBlock Text="{Binding Text}" Padding="5" TextWrapping="WrapWholeWords" />
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*" MaxWidth="100"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Button x:Name="cmdComment" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="1">
<Button x:Name="cmdRetweet" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="2">
<Button x:Name="cmdLike" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="3">
<Button x:Name="cmdMessage" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
</Grid>
</Grid>
</DataTemplate>
<DataTemplate x:Key="RetweetTemplate">
<Grid MinHeight="150" MinWidth="420">
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<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=" "/></TextBlock>
</Border>
<TextBlock Text="{Binding Path=User.Name}" />
<TextBlock Text=" retweeted"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<StackPanel Orientation="Horizontal" Padding="5">
<TextBlock Text="{Binding Path=RetweetedStatus.User.Name}" Margin="0 0 8 0" FontWeight="Bold" />
<TextBlock Text="{Binding Path=RetweetedStatus.User.ScreenName, Converter={StaticResource GetHandle}}" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
<TextBlock Text="⦁" Margin="8 0" />
<TextBlock Text="{Binding Path=RetweetedStatus.CreationDate, Converter={StaticResource FormatDate}}" />
</StackPanel>
</Grid>
<Grid Grid.Row="2">
<TextBlock Text="{Binding RetweetedStatus.Text}" Padding="5" TextWrapping="WrapWholeWords" />
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*" MaxWidth="100"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2.5*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Button x:Name="cmdComment" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="1">
<Button x:Name="cmdRetweet" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="2">
<Button x:Name="cmdLike" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
<Grid Grid.Column="3">
<Button x:Name="cmdMessage" Content="" Style="{StaticResource MetaButtons}" />
</Grid>
</Grid>
</Grid>
</DataTemplate>
<local:TweetTemplateSelector x:Key="TweetTemplateSelector"
TweetTemplate="{StaticResource TweetTemplate}"
RetweetTemplate="{StaticResource RetweetTemplate}">
</local:TweetTemplateSelector>
2
Answers
In general, you need to create match
Datatemplate
for different message type. And UWP hasDataTemplateSelector
class that could use to select specifiedDatatemplate
dynamically. For example,ListViewDataTemplateSelector.cs
Usage
I know you want less redundant code, but the less redundant code you write, the more behavioral controls you need. This will increase the complexity of your code. Although it is redundant that create
Datatemplates
for each message type, but the code is simple.No. You can’t base a template on another template. A
DataTemplate
must always be defined as a whole, i.e. you cannot “override” only some part of a template but keep the rest of it. XAML doesn’t support this.Yes, I am afraid so. You could consider creating the templates programmatically using the XamlReader class to be able to re-use as much markup as possible.