While working on a new Xamarin Forms project, I came across the need for a ContentPresenter ala Microsoft XAML. The basic idea is to use a placeholder for a piece of content (usually a ViewModel) and then supply a DataTemplate to control how it should be displayed.

A simple example might look like this:


<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>
  <controls:ContentPresenter Grid.Row="1"
               BindingContext="{Binding MyModel, Source={StaticResource Locator}}" 
               ItemTemplate="{StaticResource MyModelTemplate}"
               />

</Grid>

This goes back to some of the more “classic” MVVM patterns where we want to make our display more componentized.

In Xamarin Forms Today (v1.3.0), if you want to create a custom component, you can derive from ContentView and go to town. Add your widgets either with XAML or in code. Many times though, we don’t really need to create a new class/view directly. A DataTemplate is sufficient as we can bind to the ViewModel and use Commands to take action. These are the so-called “zero code-behind” views.

In this case, a ContentPresenter is all we need – set the BindingContext to your ViewModel and create/bind a DataTemplate. New to Forms 1.3, you can now put resources in the Application-level, so you can more easily share those instances.

Here’s the complete code, sans-usings, to implement your own. This can go either in a Shared code or PCL:

public class ContentPresenter : ContentView
{
    public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(ContentPresenter), null, propertyChanged: OnItemTemplateChanged);

    private static void OnItemTemplateChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var cp = (ContentPresenter)bindable; 

        var template = cp.ItemTemplate;
        if (template != null)
        {
            var content = (View)template.CreateContent();
            cp.Content = content;
        }
        else
        {
            cp.Content = null;
        }
    }

    public DataTemplate ItemTemplate
    {
        get
        {
            return (DataTemplate)GetValue(ItemTemplateProperty);
        }
        set
        {
            SetValue(ItemTemplateProperty, value);
        }
    }
}

If you want, you can get fancy with Triggers and change the ItemTemplate to vary based on whatever conditions you want.