The Xamarin.
Forms Calendar control allows users to easily select single dates like built-in
calendar. It provides smooth gestures for navigation between month and year
views. The key features include the following:
- Ability to disable date selection for certain dates and within a specific date range.
- Appearance customization.
- Fully Customization as it is not used any DLL, you can enhance this code according to your choice and need.
- Some of the Design is created at runtime in C#. Therefore, it is more flexible and extendable.
So Let’s Start with Design File:
TestControl.xaml
<?xml
version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="Test.TestControl"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:custom="clr-namespace:CustomControl.CalendarControl”>
<StackLayout>
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="50" />
<RowDefinition Height="1" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="1" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="6*" />
</Grid.ColumnDefinitions>
<custom:CalendarControl
x:Name="ccControls"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="4"
BackgroundColor="SkyBlue"
DateClicked="ccControls_DateClicked" />
<BoxView
x:Name="line"
Grid.Row="1"
Grid.RowSpan="24"
Grid.Column="1"
BackgroundColor="Black"
HeightRequest="1"
HorizontalOptions="FillAndExpand"
WidthRequest="1" />
<Label
x:Name="lbltime"
Grid.Row="1"
Grid.Column="2"
Margin="-3,0,-3,0"
FontSize="8"
Text="---12PM" />
<Label
x:Name="lblEvent"
Grid.Row="1"
Grid.Column="3"
FontSize="10"
LineBreakMode="TailTruncation"
Text="Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type and
scrambled it to make a type specimen book. " />
<BoxView
x:Name="horizontalline"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="3"
BackgroundColor="Black"
HeightRequest="1"
HorizontalOptions="FillAndExpand"
WidthRequest="1" />
</Grid>
</StackLayout>
</ContentPage>
Please note below Code will take three parameter and one Event Handler : Month, Year, SelectedDay and Date Clicked Event for getting
current date. For details understanding we will check the controls below and
understand how this is working.
--------------------------------------------------------------------------------------
<custom:CalendarControl
x:Name="ccControls"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="4"
BackgroundColor="SkyBlue"
DateClicked="ccControls_DateClicked" />
--------------------------------------------------------------------------------------
Code
Behind File :
(TestControl.xaml.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Test
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestControl : ContentPage
{
public TestControl()
{
InitializeComponent();
ccControls.Month
= Convert.ToString(DateTime.Now.Month);
ccControls.Year
= Convert.ToString(DateTime.Now.Year);
ccControls.SelectedDay
= Convert.ToString(DateTime.Now.Day);
}
private async void ccControls_DateClicked(object sender, EventArgs e)
{
var item = (Xamarin.Forms.Button)sender;
await DisplayAlert("Demo Project", "Date Clicked " + item.Text, "Ok");
}
}
}
Now
check below design for calander controls
CalendarControl.xaml (Design File)
<?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="CustomControls.CalendarControl">
<ContentView.Content>
<AbsoluteLayout>
<ScrollView Padding="0,0,0,0" AbsoluteLayout.LayoutBounds="0,
0, 1, 1" AbsoluteLayout.LayoutFlags="All" BackgroundColor="White"
VerticalOptions="Fill">
<StackLayout Margin="5,5,5,5">
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Image x:Name="btnBack" Grid.Row="1"
Grid.Column="1" Aspect="AspectFit" HeightRequest="15"
IsVisible="True" Source="arrow_left" VerticalOptions="Center"
WidthRequest="15">
<Image.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Tapped="btnBack_Clicked" />
</Image.GestureRecognizers>
</Image>
<Label x:Name="lblSelectedMonth" Grid.Row="1"
Grid.Column="2" FontSize="14" HorizontalOptions="Center"
IsVisible="True" Text="January" TextColor="Black"
VerticalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Tapped="lblmonth_tapped" />
</Label.GestureRecognizers>
</Label>
<Label x:Name="lblDash" Grid.Row="1"
Grid.Column="3" FontSize="14" HorizontalOptions="Center"
IsVisible="True" Text="-" TextColor="Black" VerticalOptions="Center"
/>
<Entry x:Name="lblM" IsVisible="False"
/>
<Entry x:Name="lblY" IsVisible="False"
/>
<Label x:Name="lblMonth" IsVisible="False"
/>
<Entry x:Name="lblSelectedDay" IsVisible="False"
/>
<Label x:Name="lblYear" Grid.Row="1"
Grid.Column="4" FontSize="14" HorizontalOptions="Center"
IsVisible="True" Text="2018" TextColor="Black" VerticalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Tapped="lblYear_tapped" />
</Label.GestureRecognizers>
</Label>
<Image x:Name="btnForward" Grid.Row="1"
Grid.Column="5" Aspect="AspectFit" HeightRequest="15"
HorizontalOptions="Center" IsVisible="True" Source="arrow_right"
VerticalOptions="Center" WidthRequest="15">
<Image.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Tapped="btnForward_Clicked" />
</Image.GestureRecognizers>
</Image>
</Grid>
</StackLayout>
<ContentView x:Name="gridstack" />
</StackLayout>
</ScrollView>
<ContentView x:Name="overlay" Padding="10,0"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All"
BackgroundColor="#C0808080" IsVisible="False">
<ScrollView Padding="0,0,2,0" VerticalOptions="Fill">
<StackLayout Margin="0,20,0,0" BackgroundColor="Black"
HeightRequest="400" HorizontalOptions="Center" Orientation="Vertical"
VerticalOptions="Start" WidthRequest="200">
<Label x:Name="lblDialogTitle" BackgroundColor="Black"
FontSize="14" HorizontalOptions="CenterAndExpand" Text="Select"
TextColor="White" VerticalOptions="CenterAndExpand" />
<ListView x:Name="lstView_data" BackgroundColor="White"
HasUnevenRows="False" HorizontalOptions="FillAndExpand" ItemSelected="lstView_data_ItemSelected"
SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="0" BackgroundColor="White"
Spacing="0">
<Grid Padding="5" BackgroundColor="White"
ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0"
Font="Bold" FontSize="12" IsVisible="False" Text="{Binding
dataid}" TextColor="Black" />
<Label Grid.Row="0" Grid.Column="1"
Font="Normal" FontSize="12" HorizontalOptions="CenterAndExpand"
Text="{Binding data}" TextColor="Black" VerticalOptions="CenterAndExpand"
/>
</Grid>
<BoxView BackgroundColor="#f1f1f1" HeightRequest="1"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout>
<Button x:Name="dialogclose" BackgroundColor="Black"
Clicked="dialogclose_Clicked" FontSize="14" HeightRequest="40"
Text="Close" TextColor="White" />
</StackLayout>
</StackLayout>
</ScrollView>
</ContentView>
</AbsoluteLayout>
</ContentView.Content>
</ContentView>
Code Behind File:
Note:
Following Code is also contains some dynamic control which will generate at
runtime and bind it with Xamal Code ( x:Name="overlay" )
using
System;
using
System.Collections.Generic;
using
System.Globalization;
using
System.Linq;
using
Xamarin.Forms;
using
Xamarin.Forms.Xaml;
namespace
CustomControls
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public
partial class CalendarControl : ContentView
{
public
event EventHandler DateClicked;
public
static readonly BindableProperty YearProperty = BindableProperty.Create(
propertyName:
"Year",
returnType:
typeof(string),
declaringType:
typeof(CalendarControl),
defaultValue:
"2018",
defaultBindingMode:
BindingMode.TwoWay,
propertyChanged:
YearPropertyChanged);
public
static readonly BindableProperty MonthProperty = BindableProperty.Create(
propertyName:
"Month",
returnType:
typeof(string),
declaringType:
typeof(CalendarControl),
defaultValue:
"1",
defaultBindingMode:
BindingMode.TwoWay,
propertyChanged:
MonthPropertyChanged);
public
static readonly BindableProperty SelectedDayProperty = BindableProperty.Create(
propertyName:
"SelectedDay",
returnType:
typeof(string),
declaringType:
typeof(CalendarControl),
defaultValue:
"0",
defaultBindingMode:
BindingMode.TwoWay,
propertyChanged:
SelectedDayPropertyChanged);
public
string SelectedDay
{
get
{ return GetValue(SelectedDayProperty).ToString(); }
set
{ SetValue(SelectedDayProperty, value); }
}
public string Year
{
get
{ return GetValue(YearProperty).ToString(); }
set
{ SetValue(YearProperty, value); }
}
private
static void YearPropertyChanged(BindableObject bindable, object oldValue,
object newValue)
{
var
control = (CalendarControl)bindable;
control.lblYear.Text
= newValue.ToString();
control.lblY.Text
= control.lblYear.Text;
}
private
static void SelectedDayPropertyChanged(BindableObject bindable, object
oldValue, object newValue)
{
var
control = (CalendarControl)bindable;
control.lblSelectedDay.Text
= newValue.ToString();
}
public string Month
{
get
{ return GetValue(MonthProperty).ToString(); }
set
{ SetValue(MonthProperty, value); }
}
private
static void MonthPropertyChanged(BindableObject bindable, object oldValue,
object newValue)
{
var
control = (CalendarControl)bindable;
control.lblMonth.Text
= newValue.ToString();
control.lblM.Text
= control.lblMonth.Text;
}
long
SelectedYear;
string
SelectedMonth = "";
static
int SelectedMonthInt = 0;
string
selectedday;
Grid
gridCalander;
public
CalendarControl()
{
InitializeComponent();
lblM.TextChanged
+= MonthChanged_TextChanged;
lblY.TextChanged
+= YearChanged_TextChanged;
lblM.TextChanged
+= MonthChanged_TextChanged;
lblSelectedDay.TextChanged+=
YearChanged_TextChanged;
}
private
void YearChanged_TextChanged(object sender, TextChangedEventArgs e)
{
var
y = Year;
var
m = Month;
selectedday
= SelectedDay;
SelectedYear
= Convert.ToInt64(y);
lblSelectedMonth.Text
= new DateTime(Convert.ToInt32(y), Convert.ToInt32(m),
1).ToString("MMMM");
SelectedMonthInt
= Convert.ToInt32(m);
lblYear.Text
= Convert.ToString(y);
CreateGridCalander();
CreateDate(selectedday);
}
private
void MonthChanged_TextChanged(object sender, TextChangedEventArgs e)
{
var
y = Year;
var
m = Month;
selectedday
= SelectedDay;
SelectedYear
= Convert.ToInt64(y);
lblSelectedMonth.Text
= new DateTime(Convert.ToInt32(y), Convert.ToInt32(m),
1).ToString("MMMM");
SelectedMonthInt
= Convert.ToInt32(m);
lblYear.Text
= Convert.ToString(y);
CreateGridCalander();
CreateDate(selectedday);
}
private
void CreateGridCalander()
{
#region
Grid Calander
gridCalander
= new Grid
{
BackgroundColor
= Color.LightBlue,
Padding
= 0,
ColumnSpacing
= 0,
Margin
= new Thickness(10, 0, 10, 0),
RowDefinitions
=
{
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
new
RowDefinition { Height = 50 },
new
RowDefinition { Height = 1 },
},
ColumnDefinitions
=
{
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
new
ColumnDefinition { Width = 50 },
new
ColumnDefinition { Width = 1 },
}
};
Button[]
btn = new Button[7];
string[]
weekname = new string[7] { "Mo", "Tu", "We",
"Th", "Fr", "Sa", "Su" };
for
(int i = 0; i <= 6; i++)
{
btn[i]
= new Button()
{
Text
= weekname[i],
BackgroundColor
= Color.Transparent,
FontSize
= 10,
CornerRadius
= 0,
FontAttributes
= FontAttributes.Bold,
TextColor
= Color.Black,
HorizontalOptions
= LayoutOptions.Center,
VerticalOptions
= LayoutOptions.Center
};
}
int
k = 1, l = 1;
for
(int i = 0; i <= 6; i++)
{
gridCalander.Children.Add(btn[i],
k, l);
k
= k + 2;
}
//
Grid.SetColumnSpan(Title, 5);
BoxView[]
boxr = new BoxView[8];
for
(int i = 0; i <= 7; i++)
{
boxr[i]
= new BoxView()
{
HeightRequest
= 1,
BackgroundColor
= Color.Black,
HorizontalOptions
= LayoutOptions.FillAndExpand,
};
}
k
= 0; l = 0;
//
Creating Vertical Line
for
(int i = 0; i <= 7; i++)
{
gridCalander.Children.Add(boxr[i],
k, l);
Grid.SetRowSpan(boxr[i],
15);
k
= k + 2;
}
k
= 0; l = 0;
BoxView[]
boxc = new BoxView[8];
for
(int i = 0; i <= 7; i++)
{
boxc[i]
= new BoxView()
{
HeightRequest
= 1,
BackgroundColor
= Color.Black,
HorizontalOptions
= LayoutOptions.FillAndExpand,
};
}
//
Creating Horizontal line
for
(int i = 0; i <= 7; i++)
{
gridCalander.Children.Add(boxc[i],
k, l);
Grid.SetColumnSpan(boxc[i],
15);
l
= l + 2;
}
gridstack.Content
= null;
gridstack.Content
= gridCalander;
#endregion
}
private
void btnBack_Clicked(object sender, EventArgs e)
{
var
x = SelectedMonthInt;
}
private
void btnForward_Clicked(object sender, EventArgs e)
{
}
private
void lblmonth_tapped(object sender, EventArgs e)
{
lblDialogTitle.Text
= "Select Month";
lstView_data.ItemsSource
= null;
try
{
System.Collections.Generic.List<DataMaster>
VList = new List<DataMaster>();
for
(int i = 1; i <= 12; i++)
{
VList.Add(new
DataMaster() { dataid = i, data =
CultureInfo.CurrentUICulture.DateTimeFormat.MonthNames[i - 1] });
}
lstView_data.ItemsSource
= VList;
}
catch
{
}
overlay.IsVisible
= true;
}
private
void lblYear_tapped(object sender, EventArgs e)
{
lblDialogTitle.Text
= "Select Year";
lstView_data.ItemsSource
= null;
try
{
List<int>
listYears = Enumerable.Range(1930, DateTime.Now.AddYears(50).Year - 1930 +
1).ToList();
List<DataMaster>
VList = new List<DataMaster>();
for
(int i = 1; i < listYears.Count; i++)
{
VList.Add(new
DataMaster() { dataid = i, data = Convert.ToString(listYears[i]) });
}
lstView_data.ItemsSource
= VList;
}
catch
{
}
overlay.IsVisible
= true;
}
private
void dialogclose_Clicked(object sender, EventArgs e)
{
overlay.IsVisible
= false;
}
private
void lstView_data_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
#region
FirstdayLastDay
var
item1 = (DataMaster)e.SelectedItem;
var
isNumeric = int.TryParse(item1.data, out int n);
if
(isNumeric == true)
{
SelectedYear
= Convert.ToInt64(item1.data);
lblYear.Text
= Convert.ToString(SelectedYear);
}
else
{
SelectedMonth
= Convert.ToString(item1.data);
SelectedMonthInt
= Convert.ToInt32(item1.dataid);
lblSelectedMonth.Text
= SelectedMonth;
}
if
(SelectedMonthInt == DateTime.Now.Month && SelectedYear ==
DateTime.Now.Year)
{
CreateDate(Convert.ToString(DateTime.Now.Day));
}
else
{
CreateDate("0");
}
//----------------------------------------------------------------------
#endregion
}
private
void CreateDate(string selectedday)
{
Button[]
btn = new Button[31];
//getting
First Day and Last Day---------------------------------------
DateTime
startOfMonth = new DateTime(Convert.ToInt32(SelectedYear), SelectedMonthInt,
1); //new DateTime(year, month, 1);
DateTime
endOfMonth = new DateTime(Convert.ToInt32(SelectedYear), SelectedMonthInt,
DateTime.DaysInMonth(Convert.ToInt32(SelectedYear), SelectedMonthInt)); //new
DateTime(year, month, DateTime.DaysInMonth(year, month));
//
DateTime dtSelectedDate = DateTime.Now;
string
dtFirstDayOfMonth = startOfMonth.ToString("ddd");
string
dtLastDayOfMonth = endOfMonth.ToString("ddd");
int
day = (int)startOfMonth.DayOfWeek;
gridCalander.Children.Clear();
CreateGridCalander();
for
(int i = startOfMonth.Day; i <= endOfMonth.Day; i++)
{
FontAttributes
fontattributes = FontAttributes.None;
Color
color = Color.Transparent;
Color
colortext = Color.Black;
if
(i==Convert.ToInt32(selectedday))
{
fontattributes
= FontAttributes.Bold;
color
= Color.White;
colortext
= Color.Red;
}
btn[i
- 1] = new Button()
{
Text
= i.ToString(),
FontSize
= 12,
FontAttributes=
fontattributes,
BackgroundColor
= color,
TextColor=
colortext
};
btn[i
- 1].Clicked += Calendar_Clicked;
}
int
r = 3;
int
c = 0;
if
(day == 1)
{
c
= 1;
}
else
if (day == 2)
{
c
= 3;
}
else
if (day == 3)
{
c
= 5;
}
else
if (day == 4)
{
c
= 7;
}
else
if (day == 5)
{
c
= 9;
}
else
if (day == 6)
{
c
= 11;
}
else
{
c
= 13;
}
int
m = 1;
//
adding button to gridview
for
(int k = 1; k <= 7; k++)
{
for
(int j = 1; j <= 7; j = j + 1)
{
if
(m > endOfMonth.Day)
{
break;
}
else
{
gridCalander.Children.Add(btn[m
- 1], c, r);
c
= c + 2;
m++;
if
(c == 15)
{
break;
}
}
}
c
= 1;
r
= r + 2;
}
overlay.IsVisible
= false;
}
private
void Calendar_Clicked(object sender, EventArgs e)
{
DateClicked?.Invoke(sender,
e);
//await
("Demo Project", "Date Clicked " + item.Text,
"Ok");
}
}
}
Please Follow for more post and leave comment.
Hey,
ReplyDeleteThis is really very helpful information about calendar control.
Thanks for sharing!!
Hire Xamarin Developer Texas
This code doesn't compile because the DataMaster class is missing.
ReplyDeletehere the code: public class DataMaster
Delete{
public int dataid { get; set; }
public string data { get; set; }
}
Yo Ralph Thanks for taking your time out to do this, this has helped me with 2 of my projects, i appreciate it
ReplyDeleteHow to update grid when month btnForward is clicked?
ReplyDeleteNice blog! I really loved reading through this Blog... Thanks for sharing such a very interesting post with us and keep blogging.
ReplyDeleteVisit our website-
hire xamarin developer
web development company
android development company