OnMonthCellLoadedEvent issues (was Schedule_OnMonthCellLoadedEvent not invoked on Android)

I downloaded your sample from the forum thread Customizing the month cell to help me understand how this callback works.

I built and ran it fine for iOS.

It builds and runs without error on Android, trying on a couple of different versions of Samsung device. However the month cells were not drawn in a custom manner. 

Adding a breakpoint in the constructor, I could see that it was adding the event handler. However, unlike iOS, the Android version never invoked the event handler.

        public MonthCellCustomizationPage()
        {
            InitializeComponent();
            Schedule.OnMonthCellLoadedEvent+= Schedule_OnMonthCellLoadedEvent;
        }

Please advise if this sample works for you with Android. 

Note that your sample includes version of the DLLs bundled with it. I was testing this sample because trying to use month cell customisation was crashing in iOS with the current version  15.4.0.17 (that's a separate issue)


10 Replies

SG Swathi Gopal Syncfusion Team December 4, 2017 11:33 AM UTC

Hi Andy, 
  
Thank you for Contacting Syncfusion Support. 
  
Based on your requirement, we have prepared a simple sample to customize month cell in Schedule Xamarin Forms with latest and updated ,xamarin and schedule version.In the sample included button for the month cells rendered in the view and it renders in the UI as expected in both iOS and Android platforms.Please find the sample and screenshots from the below link, 
  
  
Screenshots : Screenshots  
  
If the provided solution doesn’t meet your requirement, could you please revert us back with modifying the provided sample with more information? It will be helpful for us to analyze on it and provide you better solution. 
  
Regards, 
Swathi G 



AD Andy Dent December 6, 2017 07:18 AM UTC

Thanks for your extremely fast response and the sample code which works and has helped me diagnose one problem in my code - on Android, the OnVisibleDatesChanged event is after all the OnMonthCellLoadedEvent calls. This means I cannot load data in OnVisibleDatesChanged. On iOS, the OnVisibleDatesChanged event occurs first.

I have years of experience with using event-driven frameworks so I should know to not expect events to necessarily be in the same order across platforms, so this is a little embarrassing for me.

Something else that is now happening has me completely baffled - I am getting different values in the debug log compared to what is drawn on the screen, for Android.

I changed the month cell logic a little as shown below, so it would show the day/month in the cells. That works fine and the cells drawn show the expected values. However, the values dumped to the debug log are a month later. I know how stupid that sounds but I have tested it five times now, deleting from the device each time. I suspect this is a Xamarin problem but am extremely confused. I'm not asking for your help with this, unless it is something you know about, as the visible behaviour of the control is what I want. I am mainly writing it up here in case someone else has similar insane behaviour and gets lost debugging it.


        void Schedule_OnMonthCellLoadedEvent(object senderMonthCellLoadedEventArgs e)
        {
            var dayStr = $"{e.date.Day}/{e.date.Month}";
            Debug.WriteLine(dayStr);
            var monthCell = new StackLayout { BackgroundColor = Color.Transparent };
            var monthLabel = new Label();
            monthLabel.HeightRequest = 50;
            monthLabel.WidthRequest = 50;
            monthLabel.Margin = new Thickness(001010);
            monthLabel.BackgroundColor = Color.Green;
            monthLabel.Text = dayStr;
            monthLabel.TextColor = Color.White;
            monthCell.Children.Add(monthLabel);
            e.view = monthCell;
        }

        void Schedule_OnVisibleDatesChanged(object senderVisibleDatesChangedEventArgs e)
        {
            var firstDay = e.visibleDates[0];
            var lastDay = e.visibleDates[e.visibleDates.Count - 1];
            Debug.WriteLine($"Dates Changed: {firstDay.Day}/{firstDay.Month} to {lastDay.Day}/{lastDay.Month}");
        }

AFTER A SWIPE
The device shows January 2018, as expected with a visible range drawn of 31/12 to 10/2
The debug log shows: (Andy note - this list of strings is a month later than that displayed using the same string.)
28/1
29/1
... deleted consecutive log lines to save space here
10/3
Dates Changed: 31/12 to 10/2
(Andy note - the range in the "Dates Changed" event match the dates shown in the VISIBLE display)
 

Note I have also posted on the Xamarin Forum in case anyone answers there.


AD Andy Dent December 6, 2017 11:18 AM UTC

I think I've worked it out - the callback is to generate cells. It is not necessarily associated with cells at the time they are being drawn. If the callback has already generated a cell at some time in the recent past, it will not be invoked again for that cell.

That theory accounts for why dates in the future are also being passed to the callback, preparing them for being drawn assuming the user continues to scroll in the same direction.

Assuming I am right, I think the description Event that is raised when each cells (for every date) for month view of schedule loaded. could be enhanced a bit to warn people of this subtle behaviour. It has profound implications if you are preparing data for display.



AD Andy Dent December 6, 2017 02:21 PM UTC

Another consequence I just thought of with this behaviour is that on average, if you swipe to another month, it is generating and caching an entire extra month's worth of cells. This may explain any complaints about resource usage on Android and might be worth making an optional behaviour.


SG Swathi Gopal Syncfusion Team December 8, 2017 03:57 AM UTC

 
Hi Andy, 
 
Regarding Events: 
 
In Schedule Android, as you have mentioned OnMonthCellLoaded event will be triggered initially and later OnVisibleDatesChanged event will be triggered whereas in iOS initially while loading OnVisibleDatesChanged event will be triggered first. This is because due to layouting behavior in iOS. In android and iOS ,while swiping to next/previous view OnMonthCellLoaded event is triggered and once the swiping is completed OnVisibleDatesChanged is fired. Could you please revert us with exact requirement based on events and loading data? So that it will be helpful for us to provide you possible solution. 
 
Regarding VisibleDates range: 
As per implementation in Android, we have used three views initially to load with datas. While swiping ,we have reused the views such that only the datas are changed and the view is reused. We have handled it internally. But in the OnVisibleDatesChanged event, actual dates range will be displayed as expected. Could you please revert us with your requirement based on VisibleDatesChanged and handling data in schedule. 
 
Regards, 
Swathi G 



AD Andy Dent December 8, 2017 04:38 AM UTC

Hi Swathi.

Thanks for confirming my understanding of the event sequence. It would be really helpful to update the documentation to warn people about the order of events varying on each platform.

I'm trying to display both scattered appointments and also Roster information, where shifts that are rostered for a given day will generate appointments. The use of appointments to describe shifts is working very nicely in Day and Week views - we have a full block of say 12 hours long for each day that people are working.

For the Month view, we want to have a custom indicator drawn on rostered days, as you can see on this Play Store image.
(I am currently re-writing that app in Xamarin Forms. The original code uses native Swift 1 and Java to draw the calendars, with many limitations.)

Doing custom drawing is why I have to use OnMonthCellLoaded.

The problem with the timing of the events is that I was using the OnVisibleDatesChanged event to get updated data.

I cannot just provide a collection with all possible appointments. Rosters may go on indefinitely - they are very like your RecurrenceAppointments but with more complicated patterns for how things repeat.

One solution I have considered is just to provide a bigger range of appointments - if I generate appointments for an extra couple of months then OnVisibleDatesChanged can be used to top up the appointments for extra, off-screen months.

I am nervous about doing anything to update the Appointments list from inside OnMonthCellLoaded, in case that triggers feedback loops or has other performance implications.

The other solution I considered is to totally manage my own collections of data to draw within OnMonthCellLoaded and keep the Appointments list empty, whilst in Month view.

thanks again for the very responsive support!


AD Andy Dent December 8, 2017 04:40 AM UTC

I just renamed this issue because it's turned into a general discussion of the timing of OnMonthCellLoadedEvent, from my initial problem with it apparently not being invoked.


SG Swathi Gopal Syncfusion Team December 11, 2017 01:02 PM UTC

 
Hi Andy, 
  
Thanks for your update. 
  
We have already considered to improve Schedule online User Guide documentation in Xamarin Forms. 
  
Month cell can be customized in schedule through MonthCellStyle property or through MonthCellLoaded event of Schedule.You can refer our online user guide documentation for the same, 
  
  
Could you please confirm whether you are updating Appointments in the visibleDatesChanged event and customizing the month cell based on the appointments in schedule? So that it will be helpful for us to analyze on your requirement and provide you a possible solution.

 
Regards,
Swathi G
 



AD Andy Dent January 10, 2018 08:21 AM UTC

In order to achieve good performance, the approach I am currently taking, which seems to be working well is a combined strategy:

  1. For Day and Week views, I load the required Appointments in the VisibleDatesChanged event (and preload)
  2. For Months, I have an empty Appointments list and load from my own structures on the OnMonthCellLoaded event.
I have an optimal in-memory structure now that uses binned indexes to find fixed, bounded appointments and modulus arithmetic for repeating rostered work.

I have a few minor bugs to sort out and very little time on this project so my apologies both for the time taken to respond and my uncertainty - I will update here again once the final version is going, if I have had to change this strategy at all.

One thing I did during my investigation and design work was write a sample which used a custom iterator source for Appointments to confirm that the entire list is scanned to determine if any are in the month being displayed. This is a fairly reasonable, and flexible, design but has performance implications I don't like.

By storing my own sorted indexes, by time as Ticks, I can manage an iterator which not only knows when to stop scanning, but also optimises the starting point.


SG Swathi Gopal Syncfusion Team January 11, 2018 12:47 PM UTC

Hi Andy, 
 
Thanks for your update. 
 
As mentioned earlier, we are working in improving Schedule online User Guide documentation in Xamarin Forms. Please let us know for further assistance, we are happy to assist you. 
 
Regards, 
Swathi G 


Loader.
Up arrow icon