Scheduling-based scenarios are quite popular for the mobile environment, in which the end-user is on the go and needs to check what’s next on his schedule, immediately, without accessing his desktop machine.
In this blog post, we will guide you through the steps of using the RadCalendar component from the Telerik
UI for Xamarin suite, explaining key concepts and terms. For this purpose, we will create a simple demo application using the RadCalendar.
Application Requirements, End-User Capabilities and Raw Design
Let’s say we need an appointment-visualizing application the enables users to view, create and delete appointments. To accomplish this, we will use the RadCalendar to visualize the appointments. Alongside the calendar, we will expose two buttons. One for creating and one for removing appointments.
![calendar-rawlayout calendar-rawlayout]()
The creation/removal itself will be triggered from separate pages.
Setting Up a Blank Solution with a Ready-to-Use Template
To set up a solution, we will start by creating a blank application. We will use the
Blank App (Xamarin.Forms Portable) template provided by Xamarin. This template shares code using a portable class library. Let's name the project
X_Calendar.![calendar-newproject calendar-newproject]()
Visual Studio will create the basic structure of the solution for us, including three platform-specific projects and one portable class library.
![calendar-solution calendar-solution]()
The portable project will hold everything that can be shared between the different platforms. The rest of the projects will use the platform-specific code, such as custom renderers.
Installing NuGet packages
After having the set up solution, we can start installing the necessary NuGet packages. For every project in the solution, we need to update the Xamarin.Forms NuGet Package to the latest version.
The Android platform requires installation of the following additional packages:
- Xamarin Support Library v4
- Xamarin Support Library v7 RecyclerView
- Xamarin Support Library v8 RenderScript
- Xamarin Support Library v7 AppCompat
The last two are needed by the RadCalendar specifically. Xamarin Support Library v4 is needed by Xamarin.Forms in all cases.
Installing the packages can be done through the Package Manager Console. You can navigate to it from the
main menu >> View >> Other Windows >> Package Manager Console.
![calendar-packagemanagerconsole calendar-packagemanagerconsole]()
In the console first select
X_Calendar.Droid project:
![calendar-PMC calendar-PMC]()
Then, execute the following commands:
- Install-Package Xamarin.Android.Support.v7.AppCompat
- Install-Package Xamarin.Android.Support.v7.RecyclerView
- Install-Package Xamarin.Android.Support.v8.RenderScript
The console should report that every package is successfully installed.
Adding the Necessary References
Next, we can proceed with referencing the required assemblies in our solution. Each of the platform-specific projects should refer to the following:
- Binaries consisting of the Telerik UI for Xamarin components
- Binaries consisting of Managed Callable Wrappers for the native components
- Binaries consisting of the Telerik renderers for the components
The names of the binaries consisting of Managed Callable Wrappers for the native components start with
Telerik.Xamarin.[platformName]. The binaries consisting of the UI for Xamarin components start with
Telerik.XamarinForms. Last but not least, renderers’ binaries are named after the native binary holding the respective UI component, followed by
Renderer.[platformName]. They are part of the UI for Xamarin suite, so their full name is
Telerik.XamarinForms.[nameOfBinary]Renderer.[platformName].
Having this information in mind, we will need to add references to the following binaries in our solution:
-
In the Portable project:
- Telerik.XamarinForms.Input.dll
- Telerik.XamarinForms.Common.dll
-
In the Android project:
- Telerik.Xamarin.Android.Common.dll
- Telerik.Xamarin.Android.Input.dll
- Telerik.Xamarin.Android.Primitives.dll
- Telerik.XamarinForms.Common.dll
- Telerik.XamarinForms.Input.dll
- Telerik.XamarinForms.InputRenderer.Android.dll
-
In the iOS project:
- Telerik.Xamarin.iOS.dll
- Telerik.XamarinForms.Input.dll
- Telerik.XamarinForms.InputRenderer.iOS.dll
- Telerik.XamarinForms.Common.dll
-
In the WinPhone project:
- Telerik.Windows.Controls.Input.dll
- Telerik.Windows.Controls.Primitives.dll
- Telerik.Windows.Core.dll
- Telerik.XamarinForms.Input.dll
- Telerik.XamarinForms.InputRenderer.WinPhone.dll
- Telerik.XamarinForms.Common.dll
What are Renderers and Wrappers?
Before registering the renderers, it may be a good idea to have few words about the UI for Xamarin suite and the provided renderers. What they are and where their place is?
Each renderer is simply a class deriving from Xamarin.Forms’ ViewRenderer class. This derived class updates the Xamarin component based on the native one and vice versa. In other words, the renderers, together with the callable wrappers, are the “glue” between the native components and the Xamarin UI. If you need to dig deeper into this, you can refer to Xamarin’s Custom Renderers as well as the Architecture articles.
Registering the Required Telerik Renderers
Having this in mind, we can proceed with coupling the provided renderers with the Xamarin UI. This should be done for each of the platforms separately.
Android
In Android we need to add the following code right after the using statements of the MainActivity class:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.Android.CalendarRenderer))]
The MainActivity.cs file should look similar to this:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.Android.CalendarRenderer))]
namespace
X_Calendar.Droid
{
[Activity(Label =
"X_Calendar"
, Icon =
"@drawable/icon"
, MainLauncher =
true
, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public
class
MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected
override
void
OnCreate(Bundle bundle)
{
base
.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(
this
, bundle);
LoadApplication(
new
X_Calendar.App());
}
}
}
iOS
We can continue to the iOS project. The following code should be added in the AppDelegate class:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.iOS.CalendarRenderer))]
The AppDelegate.cs file should look similar to this:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.iOS.CalendarRenderer))]
namespace
X_Calendar.iOS
{
[Register(
"AppDelegate"
)]
public
partial
class
AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public
override
bool
FinishedLaunching(UIApplication app, NSDictionary options)
{
new
Telerik.XamarinForms.InputRenderer.iOS.CalendarRenderer();
global::Xamarin.Forms.Forms.Init();
LoadApplication(
new
X_Calendar.App());
return
base
.FinishedLaunching(app, options);
}
}
}
Windows Phone
In the WinPhone project we need to add the following code in the MainPage.xaml.cs file:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.WinPhone.CalendarRenderer))]
It should look like this:
[assembly: Xamarin.Forms.ExportRenderer(
typeof
(Telerik.XamarinForms.Input.RadCalendar),
typeof
(Telerik.XamarinForms.InputRenderer.WinPhone.CalendarRenderer))]
namespace
X_Calendar.WinPhone
{
public
partial
class
MainPage : global::Xamarin.Forms.Platform.WinPhone.FormsApplicationPage
{
public
MainPage()
{
InitializeComponent();
SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;
global::Xamarin.Forms.Forms.Init();
LoadApplication(
new
X_Calendar.App());
}
}
}
Defining the Appointment Class and Collection
Before creating the necessary screens, we should define the Appointment class and the collection that holds our list of appointments.
Defining the Appointment Class
As you would expect, the Appointment class should have
at least StartDate, EndDate and Title, so let's define it this way :
using
Telerik.XamarinForms.Input;
namespace
X_Calendar
{
public
class
Appointment : IAppointment
{
public
DateTime EndDate
{
get
;
set
;
}
public
DateTime StartDate
{
get
;
set
;
}
public
string
Title
{
get
;
set
;
}
}
}
Defining the Appointments Collection
For this part, let’s define a static field which holds all the appointments visualized in the RadCalendar component:
namespace
X_Calendar
{
public
static
class
MyStaticFields
{
public
static
ObservableCollection<Appointment> Appointments;
}
}
All three pages will interact with this field, which is why we decided to define it as static. The static classes provide easy access to resources from multiple points.
Creating the Raw Layout
After creating the blank application, referencing the correct binaries and registering the renderers we are done with setting up the solution. Now we can focus on implementing the earlier mentioned raw layout of the application. For this purpose, we will create a Forms Xaml Page, which will host a Grid panel with three rows--one for each button and one for the RadCalendar.
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
xmlns:telerik
=
"clr-namespace:Telerik.XamarinForms.Input;assembly=Telerik.XamarinForms.Input"
x:Class
=
"X_Calendar.AppointmentsPage"
>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
>
<
RowDefinition.Height
>
<
OnPlatform
x:TypeArguments
=
"GridLength"
>
<
OnPlatform.iOS
>30</
OnPlatform.iOS
>
<
OnPlatform.Android
>50</
OnPlatform.Android
>
<
OnPlatform.WinPhone
>70</
OnPlatform.WinPhone
>
</
OnPlatform
>
</
RowDefinition.Height
>
</
RowDefinition
>
<
RowDefinition
>
<
RowDefinition.Height
>
<
OnPlatform
x:TypeArguments
=
"GridLength"
>
<
OnPlatform.iOS
>30</
OnPlatform.iOS
>
<
OnPlatform.Android
>50</
OnPlatform.Android
>
<
OnPlatform.WinPhone
>70</
OnPlatform.WinPhone
>
</
OnPlatform
>
</
RowDefinition.Height
>
</
RowDefinition
>
<
RowDefinition
Height
=
"*"
/>
</
Grid.RowDefinitions
>
<
Button
Grid.Row
=
"0"
Text
=
"Add Appointment"
Clicked
=
"AddButtonClicked"
/>
<
Button
Grid.Row
=
"1"
Text
=
"Delete Appointment"
Clicked
=
"DeleteButtonClicked"
/>
<
telerik:RadCalendar
Grid.Row
=
"2"
x:Name
=
"calendar"
/>
</
Grid
>
</
ContentPage
>
For the navigation between the different pages, we will use the built-in navigation mechanism. We'll need to use the NavigationPage. In the constructor of our application, we will set the MainPage to a NavigationPage like this:
public
App()
{
// The root page of your application
MainPage =
new
NavigationPage(
new
AppointmentsPage());
}
In the code behind of our AppointmentsPage, we will also use the same navigation mechanism.
using
Telerik.XamarinForms.Input;
namespace
X_Calendar
{
public
partial
class
AppointmentsPage : ContentPage
{
static
AppointmentsPage()
{
MyStaticFields.Appointments =
new
ObservableCollection<Appointment>() {
new
Appointment() { StartDate = DateTime.Now.AddDays(-1), EndDate = DateTime.Now.AddDays(-1).AddMinutes(1), Title =
"Call Steve"
} };
MyStaticFields.Appointments.Add(
new
Appointment() { StartDate = DateTime.Now, EndDate = DateTime.Now.AddMinutes(1), Title =
"Tickets"
});
MyStaticFields.Appointments.Add(
new
Appointment() { StartDate = DateTime.Now.AddDays(3), EndDate = DateTime.Now.AddDays(3).AddMinutes(1), Title =
"Travel"
});
}
public
AppointmentsPage()
{
InitializeComponent();
this
.calendar.AppointmentsSource = MyStaticFields.Appointments;
}
protected
override
void
OnAppearing()
{
base
.OnAppearing();
}
void
AddButtonClicked(
object
sender, EventArgs e)
{
Navigation.PushAsync(
new
AddAppointmentPage(),
true
);
}
void
DeleteButtonClicked(
object
sender, EventArgs e)
{
Navigation.PushAsync(
new
DeleteAppointmentPage(),
true
);
}
}
}
This completes the raw layout of our application.
Create a Page to Add an Appointment
Next, we will create a page to add an appointment. This page should allow the user to populate the properties of an Appointment: StartDate, EndDate and Title.
To enable the user to fill in these properties, we can use two DatePickers and one Entry. To arrange them on the page, we will use a combination of StackLayouts like this:
<?xml version=
"1.0"
encoding=
"utf-8"
?>
x:Class=
"X_Calendar.AddAppointmentPage"
>
<StackLayout>
<Label Text=
"Add Appointment Page"
FontSize=
"30"
VerticalOptions=
"Center"
HorizontalOptions=
"Center"
/>
<StackLayout Orientation=
"Horizontal"
>
<Label Text=
"Start: "
/>
<DatePicker x:Name=
"startDatePicker"
HorizontalOptions=
"StartAndExpand"
/>
</StackLayout>
<StackLayout Orientation=
"Horizontal"
>
<Label Text=
"End: "
/>
<DatePicker x:Name=
"endDatePicker"
HorizontalOptions=
"StartAndExpand"
/>
</StackLayout>
<StackLayout Orientation=
"Horizontal"
>
<Label Text=
"Title: "
/>
<Entry x:Name=
"title"
WidthRequest=
"150"
/>
</StackLayout>
<Button Text=
"Done"
Clicked=
"DoneButtonClicked"
VerticalOptions=
"Center"
HorizontalOptions=
"Center"
/>
</StackLayout>
</ContentPage>
The code behind this page handles the button click event and, based on the user selection, creates an appointment.
public
partial
class
AddAppointmentPage : ContentPage
{
public
AddAppointmentPage()
{
InitializeComponent();
}
void
DoneButtonClicked(
object
sender, EventArgs e)
{
MyStaticFields.Appointments.Add(
new
Appointment()
{
StartDate = startDatePicker.Date,
EndDate = endDatePicker.Date.AddSeconds(1),
Title = title.Text ==
null
?
"(No Title)"
: title.Text
});
Navigation.PopAsync(
true
);
}
}
Create a Page to Delete an Appointment
Now we proceed with creating a page that will enable the user to delete an appointment. To visualize all available appointments, it should be able to get them and list them in a ListView component. After that, a button click will delete the user selection. To achieve this, we will use a ListView and a Button components like this:
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
x:Class
=
"X_Calendar.DeleteAppointmentPage"
>
<
StackLayout
>
<
Label
Text
=
"Delete Appointment"
FontSize
=
"30"
VerticalOptions
=
"Center"
HorizontalOptions
=
"Center"
/>
<
Grid
>
<
Grid.RowDefinitions
>
<
RowDefinition
Height
=
"50"
/>
<
RowDefinition
Height
=
"*"
/>
<
RowDefinition
Height
=
"50"
/>
</
Grid.RowDefinitions
>
<
Label
Text
=
"Select appointment to delete"
/>
<
ListView
x:Name
=
"list"
Grid.Row
=
"1"
>
<
ListView.ItemTemplate
>
<
DataTemplate
>
<
TextCell
Text
=
"{Binding Title}"
/>
</
DataTemplate
>
</
ListView.ItemTemplate
>
</
ListView
>
<
Button
Text
=
"Done"
Clicked
=
"DeleteButtonClicked"
Grid.Row
=
"2"
/>
</
Grid
>
</
StackLayout
>
</
ContentPage
>
The code behind this page will handle the click of the button, which will delete the selected appointment like this:
public
partial
class
DeleteAppointmentPage : ContentPage
{
public
DeleteAppointmentPage()
{
InitializeComponent();
this
.list.ItemsSource = MyStaticFields.Appointments;
}
void
DeleteButtonClicked(
object
sender, EventArgs e)
{
MyStaticFields.Appointments.Remove((Appointment)
this
.list.SelectedItem);
Navigation.PopAsync();
}
}
That's it! Now run the project and add a few appointments. Thanks to the underlying native Calendar components coming from
UI for iOS,
UI for Android and
UI for Windows Phone, you get the look and feel appropriate for each platform:
![calendar-all calendar-all]()
You can find the complete project at
GitHub. Of course, to run it, you need to download
Telerik UI for Xamarin.
Happy coding!