Xamarin Forms User Control

Xamarin Forms doesn’t have a control called a User Control, similar to what you might be familar with in WPF. However we can make any VisualElement, or combination of VisualElement’s into a reusable control, to use on different pages, just like a User Control.

Create Control

Create a new ContentView.

Going into the XAML, while you can keep the ContentView as your root element, I prefer to remove it and have a different layout control at the root, e.g. a Grid.

<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="Mobile.UserControl">

      <Label Text="Hello, I'm a UserControl" />
 
</Grid>

In your code behind, make sure you change the inheritance from a ContentView to a Grid.

public namespace Mobile
{
    public partial class UserControl : Grid
    {
        public UserControl()
        {
            InitializeComponent();
        }
    }
}

Using The Control

Using the control is easy, you first need to create an xmlns prefix, referencing the namespace the control is in. Then using that to place the control, where ever you want on your page.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             xmlns:control="clr-namespace:Mobile"

             x:Class="Mobile.MainPage"
             Title="Main Page">

     <control:UserControl />

</ContentPage>

Bindable Properties

Next, you might want to make your control, have a bindable property to pass data through to it, on each page it is used. First, create a Bindable Property in your UserControl. It doesn’t have to be bindable if you just want to pass a static value through, however if you want to bind to it, you must make it bindable.

public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(UserControl));

public string Text
{
    get
    {
        return (string)GetValue(TextProperty);
    }
    set
    {
        SetValue(TextProperty, value);
}

Now, in the XAML of your user control, you will want to change the label text to bind from this property. Notice, that you also set the name of the page and mark the source of the binding to the page. If you remember about BindingContexts, the user control will take the binding context of the page it is placed on. Hence you need to tell it to look in the UserControl, not the page it is placed on for the value of the property.

<Grid xmlns="http://xamarin.com/schemas/2014/forms" 
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
      x:Class="Mobile.UserControl"
      x:Name="this">
    <Label Text="{Binding Text, Source={x:Reference this}}" />
</Grid>

Going to your MainPage, you can now assign a value to the Text property. You can also use {Binding PropertyName} if you want, as this is a bindable property.

<control:UserControl Text="Hello from MainPage!" />
Microsoft MVP | Xamarin MVP | Xamarin Certified Developer |
Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts

12 Comments

  1. abdullah tahan

    you can easily bind your contentview to you viewmodel by assigning BindingContext=”{Binding}” so in your contentview you don’t really need to create new bindable properties .

    1. Adam Pedley

      The problem with that approach, is that your UserControl may have conflicting property names with whatever page you place this control on. If you want to make a truly reusable control, its best to have your own BindableProperties. There may be a few other issues that come along as well.

      But if you want it quick and easy, then yes, you can switch the BindingContext of the UserControl to your ViewModel, to just have them passed straight through.

  2. Dan Meier

    Once I’ve made my UserControl, how can I use it in other projects? Indeed, can I create a project containing only UserControls and package it up to for use in different projects?

    1. Adam Pedley

      Yes, you just create a new DLL, and place them all in there. When you reference them from your other projects, you just need to add the assembly name as well.

      xmlns:control=”clr-namespace:Mobile;assembly=MyAssemblyName”

      1. Dan Meier

        Many thanks, Adam. I’m creating the user control as a PCL project without any kind of cross-platform tie-in, compiled as a DLL, and included as a reference in a Xamarin Forms project. Works great! Just one issue, though. The user control contains an image file. I’m placing this in an Assets directory within the user control project and referencing it as… Image.Source=“Assets/ImageFile.png” However, the image doesn’t show up in the Xamarin Forms project. The user control appears, but the location where the image should appear is just blank.

        If I put the image file in the Assets directory in the Xamarin Forms UWP project and run the UWP project, the image shows up as expected within the user control. But if I can’t completely encapsulate the user control and all its resources in the referenced DLL, that seems to defeat part of the purpose of creating the DLL.

        What am I missing? I must be doing something wrong!

        1. Adam Pedley

          Images can be tricky in a DLL. UWP looks for images starting at the root, hence Assets/name.png will work, however Android starts looking for images starting at Resources/Drawable, hence you would have to put the image in Resources/Drawable/Assets/name.png

          If you want to include an image in your DLL, this can be done, I forget how off the top of my head. I think you need to look at Embedded Resource and reference that instead.

            1. Yuri

              Good guide. You can deal with embedded images either providing ImageSource in code behind or implementing markup extension

    1. Matthias Demmer

      Seems like the Binding does not work with Nullable datatypes like DateTime?
      Other types are working

      1. Dan Meier

        Matthias, my experience is that you have to include a default value in the “`BindableProperty.Create“` method in order to avoid the “`NullReferenceException“`. Here’s the general form that I’ve found successful, using as example a “`double?“` property named “`Value“` (apologies in advance if markup doesn’t work in the comments section):

        “`
        public static readonly BindableProperty ValueProperty =
        BindableProperty.Create(propertyName: nameof(Value),
        declaringType: typeof(MyUserControl),
        returnType: typeof(double?),
        defaultValue: null);
        “`

        You can also include a “`propertyChanged“` arg if you need to do something within the control other than just store the property value. This requires adding a property-specific change method, but I prefer this over hooking into the class’s “`OnPropertyChanged“` event. Here’s an example (also using the fictitious “`Value“` property):

        “`
        public static readonly BindableProperty VaueProperty =
        BindableProperty.Create(propertyName: nameof(Value),
        declaringType: typeof(MyUserControl),
        returnType: typeof(double?),
        defaultValue: null,
        propertyChanged: OnValueChanged);

        private static void OnLowerRangeLimitChanged(BindableObject bindableObject, object oldValue, object newValue)
        {
        // Get a reference to the user control class
        var userControl = (MyUserControl)bindableObject;

        // If the user control reference is null, exit immediately
        if (userControl == null) return;

        // Display the updated value in the user control
        userControl.ValueDisplay.Text = ((double?)newValue).ToString();
        }
        “`

        1. Matthias Demmer

          Hey Dan, thanks for your comment. You are right, it seems like this is possible. The problem is my DatePicker/TimePicker. They do not work with null values i guess.

Leave A Comment?