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