Reusing parts of XAML with Xamarin.Forms
Custom controls are the most common way for reusing parts of markup in Xamarin.Forms. When displaying collections, data templates can often serve as a simpler alternative with less overhead:
<StackLayout BindableLayout.ItemsSource="{Binding BasicItems}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame>
<Label Text="{Binding Title}"
FontAttributes="Bold"/>
</Frame>
<Frame>
<Label Text="{Binding Details}" />
</Frame>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
Data templates can be reused across multiple collection controls if they are defined as resources:
<ContentPage.Resources>
<DataTemplate x:Key="BasicItemTemplate">
<StackLayout>
<Frame>
<Label Text="{Binding Title}"
FontAttributes="Bold"/>
</Frame>
<Frame>
<Label Text="{Binding Details}" />
</Frame>
</StackLayout>
</DataTemplate>
</ContentPage.Resources>
They can then be referenced from the collection controls by their unique key:
<StackLayout BindableLayout.ItemsSource="{Binding BasicItems}"
BindableLayout.ItemTemplate="{StaticResource BasicItemTemplate}"/>
Repeated markup is not necessarily limited to rendering the same data type in full. For example, there could be two similar types of objects that are only partially rendered the same way:
<DataTemplate x:Key="BasicItemTemplate">
<StackLayout>
<Frame>
<Label Text="{Binding Title}"
FontAttributes="Bold"/>
</Frame>
<Frame>
<Label Text="{Binding Details}" />
</Frame>
</StackLayout>
</DataTemplate>
<DataTemplate x:Key="ItemWithPropertiesTemplate">
<StackLayout>
<Frame>
<Label Text="{Binding Title}"
FontAttributes="Bold"/>
</Frame>
<Frame>
<StackLayout BindableLayout.ItemsSource="{Binding Properties}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Label Grid.Column="0"
Text="{Binding Key}" />
<Label Grid.Column="1"
Text="{Binding Value}"
FontAttributes="Italic" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
In the above snippet, identical markup is used to render the title in both templates while the rest of the data is rendered differently. Unfortunately, no control supports data templates for rendering a single item. Therefore, they can't be used to avoid repeated markup in this case.
Control templates can be used instead, although this might not be the primary use case for them:
<ControlTemplate x:Key="TitleTemplate">
<Frame>
<Label Text="{TemplateBinding BindingContext.Title}"
FontAttributes="Bold"/>
</Frame>
</ControlTemplate>
<DataTemplate x:Key="BasicItemTemplate">
<StackLayout>
<ContentView ControlTemplate="{StaticResource TitleTemplate}" />
<Frame>
<Label Text="{Binding Details}" />
</Frame>
</StackLayout>
</DataTemplate>
<DataTemplate x:Key="ItemWithPropertiesTemplate">
<StackLayout>
<ContentView ControlTemplate="{StaticResource TitleTemplate}" />
<Frame>
<StackLayout BindableLayout.ItemsSource="{Binding Properties}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Label Grid.Column="0"
Text="{Binding Key}" />
<Label Grid.Column="1"
Text="{Binding Value}"
FontAttributes="Italic" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
They are very similar to data templates. Only data binding is defined differently. TemplateBinding
markup extension is used instead of Binding
. Since the path in template binding is relative to the control instead of its BindingContext
property, the BindingContext
must be included in the path:
<Label Text="{TemplateBinding BindingContext.Title}"
FontAttributes="Bold"/>
The control template can be applied to a ContentView
control which is typically used as the base class for custom controls:
<ContentView ControlTemplate="{StaticResource TitleTemplate}" />
A working example using this approach is available in my GitHub repository.
When you want to reuse a part of XAML in a Xamarin.Forms application without having to provide any additional logic in the code, you can take advantage of data templates for rendering collections of items and control templates for rendering individual items. This can be particularly useful in cases when the markup is only repeated inside a single page.