Xamarin.Forms Intro Part 2 – Build a Custom Control Library

UPDATE: In my example I use the namespace Xamarin.Forms, this is probably not the best namespace to use, it’s better to use CompanyName.Forms or Community.Forms.

This is the second part in a two part series introduction Xamarin.Forms. In the first part we demonstrated a basic app with Xamarin.Forms. In this part we will create a custom control library.

The library has four projects, the common PCL with references to Xamarin.Forms and a project for each of the platforms with references to Xamarin.Forms and Xamarin.Forms.Platform.(platform name), as per screenshot below.

Screen Shot 2014-06-03 at 9.47.21 pm

 

All the projects each have single important class, the PCL has a View class which in my case is the CalendarView while the platforms have a ViewRenderer which in this case is CalendarViewRenderer.

Xamarin.Forms.Calendar (Portable) – CalendarView.cs

Just to understand how it works from a consumer perspective, this  class is referenced from the calling PCL (eg the CalendarViewSample). It’s the only class you have to worry about as a consumer of the library. The renderers are called by the platform.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace Xamarin.Forms.Calendar
{
    public class CalendarView : View
    {
        public CalendarView ()
        {
        }
 
        public void NotifyDateSelected(DateTime dateSelected)
        {
            if (DateSelected != null)
                DateSelected (this, dateSelected);
        }
 
        public event EventHandler<DateTime> DateSelected;
    }
}

Xamarin.Forms.Calendar.Droid – CalendarViewRenderer.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[assembly: ExportRenderer (typeof (Xamarin.Forms.Calendar.CalendarView), typeof (CalendarViewRenderer))]
 
namespace Xamarin.Forms.Calendar.Platform.Droid
{
    public class CalendarViewRenderer : NativeRenderer 
    {
        private const string TAG = "Xamarin.Forms.Calendar";
 
        CalendarView _view;
        CalendarPickerView _pickerView;
 
        public CalendarViewRenderer ()
        {
        }
 
        protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
        {
            _view = (CalendarView)newModel;
 
            base.OnModelChanged (oldModel, newModel);
 
            LayoutInflater inflatorservice = 
                              (LayoutInflater) Context.GetSystemService(Android.Content.Context.LayoutInflaterService);
            var containerView = 
                                (LinearLayout)inflatorservice.Inflate (Resource.Layout.calendar_picker, null, false);
 
            _pickerView = containerView.FindViewById<CalendarPickerView>(Resource.Id.calendar_view);
            _pickerView.Init (new DateTime (2014, 6, 1), new DateTime (2014, 6, 30))
                .InMode (CalendarPickerView.SelectionMode.Single);
 
            _pickerView.OnDateSelected += (s, e) => {
                _view.NotifyDateSelected(e.SelectedDate);
            };
 
            SetNativeControl (containerView);
        }
    }
}

In the class above I just override the OnModelChanged method and then in that method I create a UI element. Then I wire up the OnDateSelected event and call the event on the View(which in turn goes into the consumers PCL). Finally I call SetNativeControl that add the view onto the page.

You’ll also notice the ExportRenderer line which is a assembly attribute and it links the View and the Renderers. All the other platforms are similar to this.

Xamarin.Forms.Calendar.iOS – CalendarViewRenderer.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[assembly: ExportRenderer (typeof (CalendarView), typeof (CalendarViewRenderer))]
 
namespace Xamarin.Forms.Calendar
{
    public class CalendarViewRenderer : NativeRenderer 
    {
        CalendarView _view;
        public CalendarViewRenderer ()
        {
        }
 
        protected override void OnModelSet (VisualElement model)
        {
            _view = (CalendarView)model;
            base.OnModelSet (model);
 
            var calendarView = new CalendarMonthView(DateTime.Now, true);
 
            calendarView.OnDateSelected += (date) => {
                _view.NotifyDateSelected(date);
            };
 
            base.SetNativeControl (calendarView);
        }           
    }
}

Xamarin.Forms.Calendar.WP – CalendarViewRenderer.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[assembly: ExportRenderer(typeof(CalendarView), typeof(CalendarViewRenderer))]
 
namespace Xamarin.Forms.Calendar.Platform.WP
{
    public class CalendarViewRenderer : ViewRenderer<Xamarin.Forms.Calendar.CalendarView, WPControls.Calendar>
    {
        protected override void OnModelSet()
        {
            base.OnModelSet();
            var calendar = new WPControls.Calendar();
            calendar.DateClicked +=
                (object sender, WPControls.SelectionChangedEventArgs e) =>
                {
                    Model.NotifyDateSelected(e.SelectedDate);
                };
            this.SetNativeControl(calendar);
        }
    }
}

So that’s it, creating custom controls for the Xamarin.Forms platform is pretty simple. I hope others can also enjoy making their own controls for the platform, I look forward to seeing what the community can create.

There source code for this project available on github: https://github.com/rid00z/Xamarin.Forms.Calendar

I’ve also done a little demo video, see below:


 

10 Responses

  1. Is it possible to make a custom control with multiple controls as building blocks?

    For instance, I’m wanting to build a custom spinner renderer so I can control the look and feel of it across all platforms. To do that I’m going to need both the picker object and an entry field. I was looking into just using a custom renderer, but it seems I will need to write my own spinner on android.

    I’m both new to the platform and it seems the Xamarin.Forms package is still fairly new.

  2. Would you be updating the sample for the lastest Xamarin.Forms version. Looks like there is no NativeRenderer(atleast on Android) anymore, just ViewRenderer, Having issues with SetNativeControl() on that one.

    Thanks in advance!

    1. Hi Sarthak

      If you manage to get it working can you please submit a pull request?

      Thanks

      Michael

  3. Is there an updated example? NativeRenderer appears to be missing in the newer versions.

  4. NativeRenderer appears to be missing in the newer versions.Can u please send me the working project of Xamarin.Forms.Calendar.IOS.

Leave a Reply to Jason Madden Cancel reply