Skip to content

Scheduler | Event List

A vertically scrolling event list grouped by day with infinite scroll in both directions. Uses CollectionView for virtualization (RecyclerView on Android, UICollectionView on iOS).

<scheduler:SchedulerCalendarListView
Provider="{Binding Provider}"
SelectedDate="{Binding SelectedDate}"
DefaultEventColor="CornflowerBlue"
DaysPerPage="30" />
PropertyTypeDefaultDescription
ProviderISchedulerEventProvider?nullEvent data source
SelectedDateDateOnlyTodayTwo-way bound; centers the list on this date
MinDateDateOnly?nullEarliest loadable date (stops backward scroll)
MaxDateDateOnly?nullLatest loadable date (stops forward scroll)
EventItemTemplateDataTemplate?nullCustom template for event items
DayHeaderTemplateDataTemplate?nullCustom template for day group headers
LoaderTemplateDataTemplate?nullCustom loading indicator
DaysPerPageint30Days loaded per incremental fetch
DefaultEventColorColorCornflowerBlueDefault color for event indicators
DayHeaderBackgroundColorColorTransparentBackground of day headers
DayHeaderTextColorColorBlackText color of day headers
AllowPanbooltrueEnable scroll gestures
AllowZoombooltrueEnable pinch-to-zoom
  • Grouped by day — Each day with events gets a header (e.g. “Monday, March 30, 2026”)
  • Empty days skipped — Only days with events appear in the list
  • Today indicator — Day headers show a dot for today
  • Event count — Day headers display event count (e.g. “3 events”)
  • Multi-day events — Appear in each day they span
  • Sort order — All-day events sort to top, then timed events by start time
  • Event items — Show start–end time range or “All Day” with color indicator
  • Tap events — Triggers Provider.OnEventSelected()
  • Initial load — Centers on SelectedDate and loads DaysPerPage days in each direction

The list automatically loads more data as you scroll:

  • Scrolling down — When RemainingItemsThreshold is reached, the next DaysPerPage days are appended
  • Scrolling up — When the first few items are visible, the previous DaysPerPage days are prepended
  • BoundedMinDate and MaxDate stop loading at their respective boundaries

The DayHeaderTemplate binds to CalendarListDayGroup:

public class CalendarListDayGroup : List<SchedulerEvent>
{
public DateOnly Date { get; }
public string DateDisplay { get; } // "dddd, MMMM d, yyyy"
public bool IsToday { get; }
public string EventCountDisplay { get; } // "3 events"
}
ListView.DayHeaderTemplate = new DataTemplate(() =>
{
var grid = new Grid
{
ColumnDefinitions =
{
new ColumnDefinition(GridLength.Star),
new ColumnDefinition(GridLength.Auto)
},
Padding = new Thickness(16, 8)
};
var dateLabel = new Label { FontAttributes = FontAttributes.Bold, FontSize = 16 };
dateLabel.SetBinding(Label.TextProperty,
static (CalendarListDayGroup g) => g.DateDisplay);
var countLabel = new Label { FontSize = 12, TextColor = Colors.Gray };
countLabel.SetBinding(Label.TextProperty,
static (CalendarListDayGroup g) => g.EventCountDisplay);
grid.Add(dateLabel, 0);
grid.Add(countLabel, 1);
return grid;
});

The EventItemTemplate binds to SchedulerEvent. The default shows a card with color bar, title, description, and time range.

ListView.EventItemTemplate = new DataTemplate(() =>
{
var grid = new Grid
{
ColumnDefinitions =
{
new ColumnDefinition(new GridLength(4)),
new ColumnDefinition(GridLength.Star)
},
Padding = new Thickness(8),
ColumnSpacing = 8
};
var colorBar = new BoxView { CornerRadius = 2 };
colorBar.SetBinding(BoxView.ColorProperty, static (SchedulerEvent e) => e.Color);
var title = new Label { FontSize = 14, FontAttributes = FontAttributes.Bold };
title.SetBinding(Label.TextProperty, static (SchedulerEvent e) => e.Title);
grid.Add(colorBar, 0);
grid.Add(title, 1);
return grid;
});