Computer Magic Logo
Custom XAML-based views

Wednesday, April 13, 2016

Published by Aristotelis Pitaridis

In order to demonstrate how to create our own custom XAML-based views, we will make a simple example. We will create a button which will act like a counter. Every time we click the button, the counter will increase it's value an the control will also inform the parent view about the counter change. The parent view will also be able to get the current value of the counter and it will also be able to call a method in order to reset the counter.

We right click on the Shared project of the solution and we select the New item command from the Add sub-menu. The Add New Item dialog box will appear on the screen in order to select the type of the item that we will add to the project. We select the Cross-Platform subcategory from the Visual C# category and at the right side we select the Forms Xaml Page option. At the Name textbox we type the name of the view that we want to create. For our example we will give the name CounterButton and we click the Add button.

Let's start with the XAML of the new item that we created. Below we can see the initial contents of the XAML file.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Sample.CounterButton">
	<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

We make two changes. The first change is to replace the ContntPage start and end tags to ContentView. We also replace the Label control that initially inserted in the XAML code with a button.

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Sample.CounterButton">
  <Button x:Name="Counter" Text="0" />
</ContentView>

The next thing that we have to do is to change the CounterButton.xaml.cs file. Initially the file contains the following contents.

using Xamarin.Forms;
namespace Sample
{
    public partial class CounterButton : ContentPage
    {
        public CounterButton ()
        {
            InitializeComponent ();
        }
    }
}

As we did with the XAML code by changing the ContentPage to ContentView, we will have to do the same thing here with the base class. We change the ContentPage to ContentView.

using Xamarin.Forms;
namespace Sample
{
    public partial class CounterButton : ContentView
    {
        public CounterButton ()
        {
            InitializeComponent ();
        }
    }
}

The custom view does not do anything special at the moment but it is ready to use on a ContentPage. In order to use the new view we will have to do two things. The first is to declare the namespace in the root element of the XAML ContentPage that we want to use the custom view which has to have the following format:

xmlns:local="clr-namespace:Sample"

The prefix local is usually used for the custom views but we can use another name. The Sample is the name of the namespace for the project that I created. After this declaration we can add the custom view in our XAML.

<?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:local="clr-namespace:Sample"
             x:Class="Sample.Page1">
  <ContentPage.Content>
    <StackLayout>
      <local:CounterButton x:Name="MyCounterButton" />
    </StackLayout>    
  </ContentPage.Content>
</ContentPage>

Let's create make the counter to increase it's value. We open the CounterButton.xaml.cs file and we make the following changes.

using Xamarin.Forms;
namespace Sample
{
    public partial class CounterButton : ContentView
    {
        public int CurrentValue { get; private set; }
        public CounterButton ()
        {
            InitializeComponent ();

            Counter.Clicked += Counter_Clicked;
        }

        private void Counter_Clicked(object sender, EventArgs e)
        {
            CurrentValue++;
            Counter.Text = CurrentValue.ToString();
        }
    }
}

First of all we added a property called CurrentValue which will be used in order to save the current value of the counter. The property has a private set so that only the view will be able to change it's value. We also create a method which will be called when the user clicks on the counter button. In the method we increase the value of the CurrentValue property and we change the text of the button so that it will display the new value of the counter.

If we run the application and click the button we will see that the value increase every time we click it. In the parent view we can get the value of the current value.

int i = MyCounterButton.CurrentValue;

Now we will create a method which will allow us to reset the counter. The only thing that we have to do is to create a public method in our custom view which will do the job.

using Xamarin.Forms;
namespace Sample
{
    public partial class CounterButton : ContentView
    {
        public int CurrentValue { get; private set; }
        public CounterButton ()
        {
            InitializeComponent ();

            Counter.Clicked += Counter_Clicked;
        }

        private void Counter_Clicked(object sender, EventArgs e)
        {
            CurrentValue++;
            Counter.Text = CurrentValue.ToString();
        }

        public void ResetCounter()
        {
            CurrentValue = 0;
            Counter.Text = CurrentValue.ToString();
        }
    }
}

The ResetCounter method resets the CurrentValue property to be equal to 0 and it also updates the text of the button. Now we can call the new method.

MyCounterButton.ResetCounter();

Finally we will create an event for our view. When the counter is increased we will fire an event to inform the parent view.

using Xamarin.Forms;
namespace Sample
{
    public partial class CounterButton : ContentView
    {
        public int CurrentValue { get; private set; }
        public event EventHandler CounterChanged;
        public CounterButton ()
        {
            InitializeComponent ();

            Counter.Clicked += Counter_Clicked;
        }

        private void Counter_Clicked(object sender, EventArgs e)
        {
            CurrentValue++;
            Counter.Text = CurrentValue.ToString();

            if (CounterChanged != null)
                CounterChanged(this, new EventArgs());
        }

        public void ResetCounter()
        {
            CurrentValue = 0;
            Counter.Text = CurrentValue.ToString();

            if (CounterChanged != null)
                CounterChanged(this, new EventArgs());
        }
    }
}

First of all we declared the EventHandler which has the name CounterChanged. We raise the events in two places in our code. We raise the event in the Counter_Clicked event and in the ResetCounter method because both of them change the value of the counter. Before raise the event we check if the EventHandler is null in order to make sure that the view has been attached to the event.

Now we can catch this event from the parent view like this.

using Xamarin.Forms;
namespace Sample
{
    public partial class Page1 : ContentPage
    {
        public Page1 ()
        {
            InitializeComponent ();

            MyCounterButton.CounterChanged += MyCounterButton_CounterChanged;
        }

        private void MyCounterButton_CounterChanged(object sender, EventArgs e)
        {
            int NewValue = MyCounterButton.CurrentValue;
        }
    }
}