How to select week in calendar xamarin.forms?
Calendar week selection
Xamarin.Forms calendar supports selecting the entire week using the selection mode is 'RangeSelection' and binding ' SelectedDates ' property of SfCalendar using the MVVM pattern. Calendar week day collection will be retrieved from giving a single selected date in the calendar. Based on the selected date we can generate all calendar week days and bind it to `SelectedDates`.
Step 1
Create a `ViewModel` class and add `SelectedDays` property in the `CalendarViewModel` class.
C#:
public class CalendarViewModel : INotifyPropertyChanged
{
private SelectionRange selectedDays;
/// <summary>
/// Selected Days
/// </summary>
public SelectionRange SelectedDays
{
get
{
return selectedDays;
}
set
{
selectedDays = value;
RaisePropertyChanged("SelectedDays");
}
}
/// <summary>
/// Property changed event handler
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raising Property changed event
/// </summary>
/// <param name="propertyName"></param>
public void RaisePropertyChanged(string propertyName)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Step 2
Create the `CalendarBehavior` class and wire the `SelectionChanged` event for week selection. You can get selected date from ` SelectionChanged` event and based on the selected date you can generate calendar week days by calling ` GetTotalWeekDays()`.
C#:
/// <summary>
/// Calendar Behavior class
/// </summary>
public class CalendarBehavior : Behavior<ContentPage>
{
private CalendarViewModel viewModel;
private readonly IList<int> weekNumbers = new List<int>();
/// <summary>
/// Begins when the behavior attached to the view.
/// </summary>
/// <param name="bindable">bindable value</param>
protected override void OnAttachedTo(BindableObject bindable)
{
base.OnAttachedTo(bindable);
var calendar = (bindable as MainPage).FindByName<SfCalendar>("calendar");
if (calendar == null)
{
return;
}
calendar.SelectionChanged += Calendar_SelectionChanged;
}
/// <summary>
/// Selection Changed event
/// </summary>
/// <param name="sender">return the object</param>
/// <param name="e">Selection Changed Event Args</param>
private void Calendar_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (viewModel == null)
{
viewModel = (CalendarViewModel)(sender as SfCalendar).BindingContext;
}
if (e.DateAdded.Count == 0)
{
viewModel.SelectedDays = GetTotalWeekDays(e.DateAdded[0]);
}
else
{
if (GetWeekOfYear(e.DateAdded[0]) != GetWeekOfYear(e.DateAdded[e.DateAdded.Count - 1]))
{
viewModel.SelectedDays = GetTotalWeekDays(e.DateAdded[0], e.DateAdded[e.DateAdded.Count - 1]);
}
else
{
viewModel.SelectedDays = GetTotalWeekDays(e.DateAdded[0]);
}
}
}
/// <summary>
/// Retrieve Week Days from the given date ranges.
/// </summary>
/// <param name="startDateRange">dateTime value</param>
/// <param name="endDateRange">endDateTime value</param>
/// <returns></returns>
public SelectionRange GetTotalWeekDays(DateTime startDateRange, DateTime? endDateRange = null)
{
if (endDateRange == null)
{
var days = DayOfWeek.Sunday - startDateRange.DayOfWeek;
var startDate = startDateRange.AddDays(days);
ObservableCollection<DateTime> dates = new ObservableCollection<DateTime>();
for (var i = 0; i < 7; i++)
{
dates.Add(startDate.Date);
startDate = startDate.AddDays(1);
}
return new SelectionRange(dates[0], dates[dates.Count - 1]);
}
else
{
ObservableCollection<DateTime> dates = new ObservableCollection<DateTime>();
var startDayOfWeek = DayOfWeek.Sunday - startDateRange.DayOfWeek;
var startDate = startDateRange.AddDays(startDayOfWeek);
var endDayOfWeek = DayOfWeek.Saturday - endDateRange?.DayOfWeek;
var endDate = endDateRange?.AddDays((int)endDayOfWeek);
var difference = (endDate - startDate);
for (var i = 0; i < ((TimeSpan)difference).Days + 1; i++)
{
dates.Add(startDate.Date);
startDate = startDate.AddDays(1);
}
return new SelectionRange(dates[0], dates[dates.Count - 1]);
}
}
/// <summary>
/// Method for Get Week
/// </summary>
/// <param name="time">time value</param>
/// <returns></returns>
public static int GetWeekOfYear(DateTime time)
{
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Sunday);
}
}
Step 3
Now bind the `SelectedDays` property of the `ViewModel` class with Calendar `SelectedRange` property, set the `SelectionMode` as `RangeSelection` and `CalendarViewModel` as the `BindingContext` for the calendar
XAML:
<ContentPage.Content>
<calendar:SfCalendar x:Name="calendar"
SelectionMode="RangeSelection"
SelectedRange="{Binding SelectedDays}">
<calendar:SfCalendar.BindingContext>
<local:CalendarViewModel/>
</calendar:SfCalendar.BindingContext>
</calendar:SfCalendar>
<ContentPage.Behaviors>
<local:CalendarBehavior />
</ContentPage.Behaviors>
</ContentPage.Content>
Sample outputs:
Figure 1: Selecting single of calendar week by single selection |
Figure 2: Selecting multiple of calendar weeks by swiping selected weeks. |
Sample link: https://github.com/SyncfusionExamples/calendar-week-selection

