skip to Main Content

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="&#x2981;" 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="&#xf075;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="1">
                <Button x:Name="cmdRetweet" Content="&#xf079;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="2">
                <Button x:Name="cmdLike" Content="&#xf004;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="3">
                <Button x:Name="cmdMessage" Content="&#xf0e0;" 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="&#xf079;&#160;"/></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="&#x2981;" 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="&#xf075;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="1">
                <Button x:Name="cmdRetweet" Content="&#xf079;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="2">
                <Button x:Name="cmdLike" Content="&#xf004;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="3">
                <Button x:Name="cmdMessage" Content="&#xf0e0;" Style="{StaticResource MetaButtons}" />
            </Grid>
        </Grid>
    </Grid>
</DataTemplate>

<local:TweetTemplateSelector x:Key="TweetTemplateSelector"
    TweetTemplate="{StaticResource TweetTemplate}"
    RetweetTemplate="{StaticResource RetweetTemplate}">
</local:TweetTemplateSelector>

2

Answers


  1. In general, you need to create match Datatemplate for different message type. And UWP has DataTemplateSelector class that could use to select specified Datatemplate dynamically. For example,

    ListViewDataTemplateSelector.cs

    public class ListViewDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate MaleData { set; get; }
        public DataTemplate FemaleData { set; get; }
    
        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            if (item is Male)
            {
                return MaleData;
            }
            return FemaleData;
        }
    }
    

    Usage

    <Page.Resources>
        <DataTemplate x:Key="MaleData">
            <Grid>
               <Border>
                   <Grid Margin="10,10,10,10">
                        <StackPanel>
                            <TextBlock Text="Name"></TextBlock>
                            <TextBlock Text="{Binding Path=Name}"></TextBlock>
                            <TextBlock Text="Height"></TextBlock>
                            <TextBlock Text="{Binding Path=Stature}"></TextBlock>
                        </StackPanel>
                    </Grid>
               </Border>
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="FemaleData">
            <Grid>
                <Border>
                    <Grid Margin="10,10,10,10">
                        <StackPanel>
                            <TextBlock Text="Name"></TextBlock>
                            <TextBlock Text="{Binding Path=Name}"></TextBlock>
                            <TextBlock Text="Age"></TextBlock>
                            <TextBlock Text="{Binding Path=Year}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </Border>
            </Grid>
        </DataTemplate>
        <local:ListViewDataTemplateSelector x:Key="Selector" FemaleData="{StaticResource FemaleData}"
                                            MaleData="{StaticResource MaleData}"></local:ListViewDataTemplateSelector>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{x:Bind View.HumanWorld}"
                  ItemTemplateSelector="{StaticResource Selector}"></ListView>
        <TextBlock Text="http://blog.csdn.net/lindexi_gd" VerticalAlignment="Bottom"></TextBlock>
    </Grid>
    

    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?

    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.

    Login or Signup to reply.
  2. 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?

    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.

    Or am I stuck making a near-duplicate template for each possible combination to accommodate media and retweeted tweets with media?

    Yes, I am afraid so. You could consider creating the templates programmatically using the Xaml​Reader class to be able to re-use as much markup as possible.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search