Hello,
I have a view where I have 3 different XamSchedulers, each with his own view mode. I toggle the visibility of each one based on a selection of dropdown. Agenda and Monthly views are working fine, but when I select the Weekly View is causing the application to crash with an Invalid Operation Exception : "Sequence contains no elements".
View
... <Grid> <!--#region Monthly View --> <ig:XamScheduler x:Name="MonthlyScheduler" ViewMode="MonthView" IsVisible="{Binding IsMonthlyVisible}" ViewSplitOrientation="Vertical" MonthViewAgendaVisibility="Visible" MonthViewNameVisibility="Visible" MonthViewNameFontSize="20" MonthViewDayFontSize="12" MonthViewDayOfWeekHeaderVisibility="Visible" MonthViewDayOfWeekHeaderFontSize="12" MonthViewLeadingDayVisibility="Visible" MonthViewLeadingDayFontSize="12" MonthViewTrailingDayVisibility="Visible" MonthViewTrailingDayFontSize="12" MonthViewWeekNumberVisibility="Visible" MonthViewWeekNumberFontSize="12" MonthViewScrollDirection="Horizontal" SelectedDate="{Binding SelectedDate, Mode=TwoWay}" SelectedAppointment="{Binding SelectedAppointment, Mode=TwoWay}" SelectedDateChanged="MonthlyScheduler_SelectedDateChanged"> <ig:XamScheduler.DataSource> <ig:ScheduleListDataSource AppointmentItemsSource="{Binding Appointments, Mode=TwoWay}" ResourceItemsSource="{Binding Resources, Mode=TwoWay}" /> </ig:XamScheduler.DataSource> </ig:XamScheduler> <!--#endregion--> <!--#region Weekly View --> <ig:XamScheduler x:Name="WeekScheduler" ViewMode="WeekView" IsVisible="{Binding IsWeeklyVisible}" WorkingHoursDisplayMode="WorkingHoursOnly" AppointmentSelected="WeekScheduler_AppointmentSelected" SelectedDate="{Binding SelectedDate, Mode=TwoWay}" SelectedAppointment="{Binding SelectedAppointment, Mode=TwoWay}"> <ig:XamScheduler.DataSource> <ig:ScheduleListDataSource AppointmentItemsSource="{Binding Appointments, Mode=TwoWay}" ResourceItemsSource="{Binding Resources, Mode=TwoWay}" /> </ig:XamScheduler.DataSource> </ig:XamScheduler> <!--#endregion--> <!--#region Agenda View --> <ig:XamScheduler x:Name="AgendaScheduler" ViewMode="AgendaView" AgendaViewMinimumDate="{Binding MinimumDate}" AgendaViewMaximumDate="{Binding MaximumDate}" SelectedDate="{Binding SelectedDate, Mode=TwoWay}" SelectedAppointment="{Binding SelectedAppointment, Mode=TwoWay}" IsVisible="{Binding IsAgendaVisible}" SelectedDateChanged="AgendaScheduler_SelectedDateChanged"> <ig:XamScheduler.DataSource> <ig:ScheduleListDataSource AppointmentItemsSource="{Binding Appointments, Mode=TwoWay}" ResourceItemsSource="{Binding Resources, Mode=TwoWay}" /> </ig:XamScheduler.DataSource> </ig:XamScheduler> <!--#endregion--> </Grid> ...
View Code
public partial class SchedulesPage : ContentView { SchedulesPageVM viewModel; public SchedulesPage() { InitializeComponent(); viewModel = new SchedulesPageVM(GlobalData.Cl, StartDatePicker, EndDatePicker); BindingContext = viewModel; WorkingHoursCollection shift = new WorkingHoursCollection(); shift.Add(new TimeSpan(GlobalData.GeneralParameters.StartHour, 0, 0), new TimeSpan(GlobalData.GeneralParameters.EndHour, 0, 0)); WeekScheduler.DaysOfWeekSettings = new Infragistics.Scheduler.ScheduleDaysOfWeekSettings() { Monday = new ScheduleDayOfWeekSettings() { IsWorkday = true, WorkingHours = shift }, Tuesday = new ScheduleDayOfWeekSettings() { IsWorkday = true, WorkingHours = shift }, Wednesday = new ScheduleDayOfWeekSettings() { IsWorkday = true, WorkingHours = shift }, Thursday = new ScheduleDayOfWeekSettings() { IsWorkday = true, WorkingHours = shift }, Friday = new ScheduleDayOfWeekSettings() { IsWorkday = true, WorkingHours = shift }, Saturday = new ScheduleDayOfWeekSettings() { IsWorkday = false, WorkingHours = shift }, Sunday = new ScheduleDayOfWeekSettings() { IsWorkday = false, WorkingHours = shift } }; } private void GoToToday(object sender, EventArgs e) { viewModel.SelectedDate = DateTime.Now; if (viewModel.SelectedCalendar.Text == "Calendário") { MonthlyScheduler.EnsureDayVisibleInMonthView(DateTime.Now); } else if (viewModel.SelectedCalendar.Text == "Semanal") { WeekScheduler.EnsureDayVisibleInDayOrWeekView(DateTime.Now); } else { AgendaScheduler.EnsureDayVisibleInAgendaView(DateTime.Now); } } private void MonthlyScheduler_SelectedDateChanged(object sender, SelectedDateChangedEventArgs e) { MonthlyScheduler.EnsureDayVisibleInMonthView(viewModel.SelectedDate); } }
View Model
public class SchedulesPageVM : BaseViewModel, INotifyPropertyChanged { #region State private DateTime selectedDate; private DateTime minimumDate; private DateTime maximumDate; private string searchText; private SearchScheduleModel searchSchedule; private ObservableCollection<Appointment> appointments = new ObservableCollection<Appointment>(); private ObservableCollection<ScheduleResource> resources = new ObservableCollection<ScheduleResource>(); private ObservableCollection<ScheduleModel> schedules = new ObservableCollection<ScheduleModel>(); private Appointment selectedAppointment; private ObservableCollection<MiniModel> calendarOptions = new ObservableCollection<MiniModel>(); private MiniModel selectedCalendar; private List<string> listCalendarOptions = new List<string>(); private bool isWeeklyVisible; private bool isMonthlyVisible; private bool isAgendaVisible; #endregion #region Notify Property Changed private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion #region Components, Properties, Images & Commands #region Components public DatePicker StartDatePicker { get; set; } public DatePicker EndDatePicker { get; set; } #endregion #region Properties public Preferencias Preferences { get; set; } public parapda Parapda { get; set; } public Cl CurrentEntity { get; set; } public DateTime SelectedDate { get { return selectedDate; } set { selectedDate = value; OnPropertyChanged("SelectedDate"); if (SelectedAppointment != null) SelectedAppointment = null; } } public DateTime MinimumDate { get { return minimumDate; } set { minimumDate = value; OnPropertyChanged("MinimumDate"); SearchSchedule = new SearchScheduleModel() { BeginDate = this.MinimumDate, EndDate = this.MaximumDate, SearchText = this.SearchText }; if (MaximumDate.Subtract(MinimumDate).TotalDays > 186) { UiInterfaceHelper.AlertNotification(LangSchedules.ExceededTimeWarningMessage); } } } public DateTime MaximumDate { get { return maximumDate; } set { maximumDate = value; OnPropertyChanged("MaximumDate"); SearchSchedule = new SearchScheduleModel() { BeginDate = this.MinimumDate, EndDate = this.MaximumDate, SearchText = this.SearchText }; if (MaximumDate.Subtract(MinimumDate).TotalDays > 186) { UiInterfaceHelper.AlertNotification(LangSchedules.ExceededTimeWarningMessage); } } } public string SearchText { get { return searchText; } set { searchText = value; OnPropertyChanged("SearchText"); SearchSchedule = new SearchScheduleModel() { BeginDate = this.MinimumDate, EndDate = this.MaximumDate, SearchText = this.SearchText }; } } public SearchScheduleModel SearchSchedule { get { return searchSchedule; } set { searchSchedule = value; OnPropertyChanged("SearchSchedule"); } } public ObservableCollection<Appointment> Appointments { get { return appointments; } set { appointments = value; OnPropertyChanged("Appointments"); } } public ObservableCollection<ScheduleResource> Resources { get { return resources; } set { resources = value; OnPropertyChanged("Resources"); } } public ObservableCollection<ScheduleModel> Schedules { get { return schedules; } set { schedules = value; OnPropertyChanged("Schedules"); } } public Appointment SelectedAppointment { get { return selectedAppointment; } set { selectedAppointment = value; OnPropertyChanged("SelectedAppointment"); if (selectedAppointment != null && GlobalData.CanExecute) { Device.BeginInvokeOnMainThread(async () => { await OpenUpdateScheduleFrame(); }); } } } public ObservableCollection<MiniModel> CalendarOptions { get { return calendarOptions; } set { calendarOptions = value; OnPropertyChanged("CalendarOptions"); } } public MiniModel SelectedCalendar { get { return selectedCalendar; } set { selectedCalendar = value; OnPropertyChanged("SelectedCalendar"); } } public List<string> ListCalendarOptions { get { return listCalendarOptions; } set { listCalendarOptions = value; OnPropertyChanged("ListCalendarOptions"); } } public bool IsWeeklyVisible { get { return isWeeklyVisible; } set { isWeeklyVisible = value; OnPropertyChanged("IsWeeklyVisible"); } } public bool IsMonthlyVisible { get { return isMonthlyVisible; } set { isMonthlyVisible = value; OnPropertyChanged("IsMonthlyVisible"); } } public bool IsAgendaVisible { get { return isAgendaVisible; } set { isAgendaVisible = value; OnPropertyChanged("IsAgendaVisible"); } } #endregion #region Images public ImageSource CalendarIcon { get { return ImageSource.FromResource("WaveTradeX.Assets.Icons.ic_calendar.png"); } } #endregion #region Commands public ICommand TriggerDatePickerCommand => new Command<string>((parameter) => TriggerDatePicker(parameter)); public ICommand OpenSheduleFrameCommand { get { return new Command<View>(async (v) => await OpenSheduleFrame(), (v) => GlobalData.CanExecute && !IsNotConnected); } } public ICommand ActionCommand => new Command<MaterialMenuResult>((s) => RefreshAgenda(s)); public SearchScheduleCommand SearchSchedulerCommand { get; set; } #endregion #endregion #region Constructor public SchedulesPageVM(Cl currentEntity, DatePicker startDatePicker, DatePicker endDatePicker) { try { _ = FileUtils.WriteLogAsync(LogMessageType.ViewModel, "SchedulesPageVM", "SchedulesPageVM"); CurrentEntity = currentEntity; Preferences = GlobalData.Preferencia; Parapda = GlobalData.Parapda; StartDatePicker = startDatePicker; EndDatePicker = endDatePicker; SearchSchedulerCommand = new SearchScheduleCommand(this); CalendarOptions = ScheduleActionsHelper.GetCalendarOptions(); ListCalendarOptions = CalendarOptions.Select(actions => actions.Text).ToList(); SelectedCalendar = string.IsNullOrEmpty(Preferences.AgendaModeSelected) ? CalendarOptions[0] : CalendarOptions.Where(item => item.Description.Equals(Preferences.AgendaModeSelected)).FirstOrDefault(); SwitchScheduler(SelectedCalendar.Text); // Update Preferences Preferences.AgendaModeSelected = SelectedCalendar.Description; PreferenciasHelper.UpdatePreferencia(Preferences); Appointments = new ObservableCollection<Appointment>(); Resources = new ObservableCollection<ScheduleResource>(); SelectedDate = DateTime.Now; MinimumDate = DateTime.Now.AddMonths(-3); MaximumDate = DateTime.Now.AddMonths(3); if (GlobalData.IsMain) HomePage.viewModel.EventRefreshSchedules += async (sender, e) => await GetAllSchedulesAsync(); else { if(CurrentEntity.IsLead) LeadDetailsPage.viewModel.EventGetAllSchedules += async (sender, e) => await GetAllSchedulesAsync(); else ClientDetailsPage.viewModel.EventGetAllSchedules += async (sender, e) => await GetAllSchedulesAsync(); } } catch (Exception ex) { _ = FileUtils.WriteLogAsync(LogMessageType.Error, "SchedulesPageVM", string.Format("SchedulesPageVM : {0}", ex.Message)); } } #endregion #region Methods #region Trigger Date Picker private void TriggerDatePicker(string parameter) { switch (parameter) { case "Start": StartDatePicker.Focus(); break; case "End": EndDatePicker.Focus(); break; } } #endregion #region Change Refresh public bool ChangeRefresh(int index) { bool result = false; string strSelected = ListCalendarOptions[index]; if (strSelected != SelectedCalendar.Text) { SelectedCalendar = CalendarOptions.Where(item => item.Text.Equals(strSelected)).FirstOrDefault(); Preferences.AgendaModeSelected = SelectedCalendar.Description; PreferenciasHelper.UpdatePreferencia(Preferences); SwitchScheduler(strSelected); result = true; } return result; } public void SwitchScheduler(string strScheduleType) { switch (strScheduleType) { case "Calendário": IsMonthlyVisible = true; IsWeeklyVisible = false; IsAgendaVisible = false; break; case "Agenda": IsMonthlyVisible = false; IsWeeklyVisible = false; IsAgendaVisible = true; break; case "Semanal": IsMonthlyVisible = false; IsWeeklyVisible = true; IsAgendaVisible = false; break; } } #endregion #region Refresh Agenda public async Task RefreshAgenda(MaterialMenuResult selected) { if (ChangeRefresh(selected.Index)) { var config = new ProgressDialogConfig() .SetTitle("") .SetIsDeterministic(false) .SetMaskType(MaskType.Gradient); using (UserDialogs.Instance.Progress(config)) { try { await Task.Delay(100); await GetAllSchedulesAsync(); } catch (Exception ex) { Console.WriteLine(ex.Message); _ = FileUtils.WriteLogAsync(LogMessageType.Error, "SchedulesPageVM", "RefreshAgenda()" + ex.Message); } } } } #endregion #region Search For Schedule public void SearchForSchedules(SearchScheduleModel searchSchedule) { GetAllSchedulesAsync(searchSchedule); } #endregion #region Get All Schedules /// <summary> /// Get all schedules /// </summary> private async Task GetAllSchedulesAsync(SearchScheduleModel search = null) { try { if (!IsNotConnected) { bool serverStatus = false; using (await MaterialDialog.Instance.LoadingDialogAsync(LangSync.ServerStatus)) { serverStatus = await StatusRequestHelper.CheckWSStatus(); } if (serverStatus) { var config = new ProgressDialogConfig() .SetTitle("") .SetIsDeterministic(false) .SetMaskType(maskType: MaskType.Gradient); using (UserDialogs.Instance.Progress(config)) { bool IsSearch = false; bool IsDescriptiveSearch = false; ScheduleFormRequest form = new ScheduleFormRequest() { SellerNumber = Parapda.Vendedor, }; // If its a search if (search != null) { IsSearch = true; // Check if dates not empty if (search.BeginDate != null && search.EndDate != null) { form.BeginDate = search.BeginDate; form.EndDate = search.EndDate; } // If search text is not empty if (!string.IsNullOrEmpty(search.SearchText)) { IsDescriptiveSearch = true; form.SearchText = search.SearchText; } } // Not being searched, set interval between 6 months else { form.BeginDate = DateTime.Now.AddMonths(-3); form.EndDate = DateTime.Now.AddMonths(3); } Schedules = new ObservableCollection<ScheduleModel>(await ScheduleServiceHelper.GetAllSchedules(form)); foreach (ScheduleModel schedule in Schedules) { schedule.DateStart = schedule.DateStart; // + DateTimeOffset.Now.Offset; schedule.DateEnd = schedule.DateEnd; // + DateTimeOffset.Now.Offset; } Appointments = GenerateAppointments(Schedules); Resources = GenerateResource(); if (IsSearch) { if (schedules.Count != 0) { if (IsDescriptiveSearch) { SearchScheduleResultsPopup page = new SearchScheduleResultsPopup(Schedules, GetSearchSelection); await PopupNavigation.Instance.PushAsync(page); } else { ChangeRefresh(0); } } } } } else { await UiInterfaceHelper.ShowSnackbar("blueBerryColor", LangGeneral.ServerUnreachable, LangGeneral.Close, 3000); } } else await UiInterfaceHelper.ShowSnackbar("blueBerryColor", LangGeneral.NoConnection, LangGeneral.Close, 3000); } catch (Exception ex) { _ = FileUtils.WriteLogAsync(LogMessageType.Error, "SchedulesPageVM", string.Format("GetAllSchedulesAsync() : {0}", ex.Message)); } } #endregion #region Generate Appointments /// <summary> /// Generate a list of all the appointments to be displayed on the view /// based on what is in the DB /// </summary> /// <param name="schedules"></param> /// <returns></returns> private ObservableCollection<Appointment> GenerateAppointments(ObservableCollection<ScheduleModel> schedules) { Random generator = new Random(); var items = new ObservableCollection<Appointment>(); foreach (ScheduleModel schedule in schedules) { string strOwner = string.Empty; string strLocal = string.Empty; bool bOwnerAssigned = false; bool bAssocLocal = false; if (!string.IsNullOrEmpty(schedule.CuName) && !string.IsNullOrEmpty(schedule.CuNumber)) { strOwner = schedule.CuName; bOwnerAssigned = true; } else if (!string.IsNullOrEmpty(schedule.PoName) && !string.IsNullOrEmpty(schedule.PoNumber)) { strOwner = schedule.PoName; bOwnerAssigned = true; } if (!string.IsNullOrEmpty(schedule.Address)) { strLocal = schedule.Address; bAssocLocal = true; } items.Add(new Appointment() { Start = schedule.DateStart, End = schedule.DateEnd, Subject = schedule.Description, Location = bOwnerAssigned ? strOwner : (bAssocLocal ? strLocal : "Indefinido"), ResourceId = "Resource-" + generator.Next(0, 20), Id = schedule.Stamp.ToString() }); } return items; } #endregion #region Generate Appointment private Appointment GenerateAppoiment(ScheduleModel scheduleModel) { Random generator = new Random(); return new Appointment() { Start = scheduleModel.DateStart, End = scheduleModel.DateEnd, Subject = scheduleModel.Description, Location = scheduleModel.Address, ResourceId = "Resource-" + generator.Next(0, 20), Id = scheduleModel.Stamp.ToString() }; } #endregion #region Generate Color Schemes /// <summary> /// Generates Color Schemes /// </summary> /// <returns></returns> public ObservableCollection<ScheduleResource> GenerateResource() { var resources = new ObservableCollection<ScheduleResource>(); var schemes = Enum.GetValues(typeof(ScheduleResourceColorScheme)); var schemesList = schemes.Cast<ScheduleResourceColorScheme>().ToList(); for (int i = 0; i < 20; i++) { var schemeId = "Resource-" + i; var schemeColor = schemesList[i % schemesList.Count]; resources.Add(new ScheduleResource(schemeId) { ColorScheme = schemeColor }); } return resources; } #endregion #region Open Schedule Frame private async Task OpenSheduleFrame() { if (GlobalData.CanExecute) { GlobalData.CanExecute = false; using (await MaterialDialog.Instance.LoadingDialogAsync(LangGeneral.Loading)) { await Task.Delay(500); ScheduleModel newSchedule = new ScheduleModel(); DateTime nowDateTime = DateTime.Now; bool hourExtension = false; if (!ValidateDateSelection(selectedDate, nowDateTime, ref hourExtension)) { // Show warning if (!await UiInterfaceHelper.WarningDialog(LangSchedules.DateInvalidTitle, LangSchedules.DateInvalidMessage)) { GlobalData.CanExecute = true; return; } } if (CurrentEntity != null) newSchedule.Address = CurrentEntity.Address; else newSchedule.Address = string.Empty; // If its the same day but its past 09:00, set it to the next current hour if (hourExtension) { newSchedule.DateStart = new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, nowDateTime.Hour + 1, 00, 00); newSchedule.DateEnd = new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, nowDateTime.Hour + 2, 00, 00); } else { newSchedule.DateStart = new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, 9, 00, 00); newSchedule.DateEnd = new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, 10, 00, 00); } // OpSchedulePopup page = new OpSchedulePopup(cl, 0, false, "Main", CreateOrUpdateSchedule); // SchedulePopup page = new SchedulePopup(Cl, newSchedule, false, "Main", CreateOrUpdateSchedule); ScheduleAuxData.SelectedSchedule = newSchedule; // NewSchedulePopup page = new NewSchedulePopup("Main", CreateOrUpdateSchedule); string strOrigin = CurrentEntity != null ? "Client" : "Main"; NewSchedulePopup page = new NewSchedulePopup(CurrentEntity, newSchedule, false, strOrigin, CreateOrUpdateSchedule); await PopupNavigation.Instance.PushAsync(page); GlobalData.PopupOpened = true; } GlobalData.CanExecute = true; } } #endregion #region Open Update Schedule Frame private async Task OpenUpdateScheduleFrame() { if (GlobalData.CanExecute) { GlobalData.CanExecute = false; using (await MaterialDialog.Instance.LoadingDialogAsync(LangGeneral.Loading)) { await Task.Delay(500); if (SelectedAppointment != null) { ScheduleModel selectedSchedule = Schedules.Where(item => item.Stamp.ToString().Contains(SelectedAppointment.Id)).FirstOrDefault(); string strOrigin = CurrentEntity != null ? "Client" : "Main"; NewSchedulePopup page = new NewSchedulePopup(CurrentEntity, selectedSchedule, true, strOrigin, CreateOrUpdateSchedule); await PopupNavigation.Instance.PushAsync(page); GlobalData.PopupOpened = true; } } GlobalData.CanExecute = true; } } #endregion #region Validate Date Selection private bool ValidateDateSelection(DateTime selectedDate, DateTime currentTime, ref bool needsHourExtension) { bool result = true; // Convert Dates to string, isolating year, month and date string strSelectedDate = selectedDate.ToString("yyyy-MM-dd"); string strCurrentTime = currentTime.ToString("yyyy-MM-dd"); DateTime dateSelectedParsed = DateTime.Parse(strSelectedDate, CultureInfo.InvariantCulture); DateTime dateCurrentParsed = DateTime.Parse(strCurrentTime, CultureInfo.InvariantCulture); // if the selected date is previously to the current datetime if (dateSelectedParsed < dateCurrentParsed) { result = false; } // Date is the same, check the hour else if (dateSelectedParsed == dateCurrentParsed) { if (currentTime.Hour < 9) needsHourExtension = false; else needsHourExtension = true; } else needsHourExtension = false; return result; } #endregion #region Create or Update Schedule private void CreateOrUpdateSchedule(SchedulerEventArgs args) { if (args.IsConfirm) { var config = new ProgressDialogConfig() .SetTitle("") .SetIsDeterministic(false) .SetMaskType(maskType: MaskType.Gradient); using (UserDialogs.Instance.Progress(config)) { switch (args.Option) { case "created": Appointments.Add(GenerateAppoiment(args.Scheduler)); Schedules.Add(args.Scheduler); break; case "updated": ScheduleModel editSchdule = Schedules.First(schedule => schedule.Stamp.Equals(args.Scheduler.Stamp)); if (editSchdule != null) { Schedules.Remove(editSchdule); Schedules.Add(args.Scheduler); } Appointment editAppoiment = Appointments.First(appoiment => appoiment.Id.Equals(args.Scheduler.Stamp.ToString())); if (editAppoiment != null) Appointments = GenerateAppointments(Schedules); break; case "deleted": ScheduleModel deleteSchdule = Schedules.First(schedule => schedule.Stamp.Equals(args.Scheduler.Stamp)); if (deleteSchdule != null) Schedules.Remove(deleteSchdule); if (deleteSchdule != null) Appointments = GenerateAppointments(Schedules); break; } } } } #endregion #region Get Search Selection private void GetSearchSelection(SchedulerEventArgs args) { if (args.IsConfirm) { var config = new ProgressDialogConfig() .SetTitle("") .SetIsDeterministic(false) .SetMaskType(maskType: MaskType.Gradient); using (UserDialogs.Instance.Progress(config)) { switch (args.Option) { case "selected": SelectedDate = args.Scheduler.DateStart; break; } } } } #endregion #endregion }