Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!
Calendar Store Releases
v5.4.0 - August 2026
Section titled “v5.4.0 - August 2026”BREAKINGFeature
Query() is now a fluent async builder. ICalendarStore.Query() returns a CalendarEventQuery instead of an IQueryable<CalendarEvent>: configure it with ForCalendar / From / To / Between / Where(Func<CalendarEvent,bool>) / TitleContains / OrderBy / ThenBy / Skip / Take, then run it with ToListAsync(ct), FirstOrDefaultAsync(ct) or CountAsync(ct). This removes the whole class of “blocking enumeration on the UI thread” bugs — the native read is awaited off the calling thread — and it takes a CancellationToken, which the IQueryable never could. Rewrite store.Query().Where(e => e.CalendarId == id && e.Start >= from && e.End <= to).OrderBy(e => e.Start).ToList() as await store.Query().ForCalendar(id).Between(from, to).OrderBy(CalendarEventSortField.Start).ToListAsync(ct). See Querying.Enhancement
Sorting (
OrderBy/ThenBy over CalendarEventSortField.Start/End/Title, each with a descending flag) is now built into the query rather than something you bolt on afterwards.Chore
The LINQ expression visitor, provider and interpreter are gone — no expression trees are built or walked at query time any more, which is a meaningful win under AOT/trimming.
Feature
Per-calendar AI tool access.
ICalendarAIToolBuilder gained AddCalendar(string calendarId, CalendarAICapabilities) and AddCalendars(IEnumerable<string>, CalendarAICapabilities), so the agent’s allow-list can differ per calendar — read-only on one, read/write on another — while AddCalendar(capabilities) still sets the global default for every calendar. A per-calendar entry replaces the global set, so it can widen or narrow access, and CalendarAICapabilities.None hides a calendar from the agent entirely. The tools enforce it on every call: list_calendars returns only allowed calendars (each with an allowedOperations array), search_events searches only readable ones, and get_event / create_event / update_event / delete_event refuse calendars outside the filter. See AI Tools.Enhancement
New
AddCalendarAITools(Action<IServiceProvider, ICalendarAIToolBuilder>) overload — the callback runs when CalendarAITools is first resolved, so the allowed calendar ids can come from your own services (a settings store, the user’s calendar picker) rather than having to be known at registration time.v5.3.0 - July 26, 2026
Section titled “v5.3.0 - July 26, 2026”Feature
Shiny.Calendar — new cross-platform calendar library.
ICalendarStore provides full CRUD on calendars and events plus a LINQ Query() over events. Register with builder.Services.AddCalendarStore().FeatureiOS
EventKit backend for iOS, Mac Catalyst, and macOS, with iOS 17 full / write-only access via
CalendarAccessType.FeatureAndroid
CalendarContract backend with
READ_CALENDAR / WRITE_CALENDAR permissions and full event CRUD.FeatureWindows
Best-effort
AppointmentStore backend — reads/queries all calendars; create/update/delete are supported inside an app-owned calendar (system-calendar writes throw).Feature
LINQ querying —
IQueryable<CalendarEvent> pushes calendar id and the Start/End window down to the native fetch, with an exact in-memory pass for everything else.Feature
Rich event model — attendees, reminders, availability, URL, and read-only recurrence/organizer.
EventAttendee.ResolveContact(IContactStore) bridges an attendee to a device contact by email.Feature
Shiny.Calendar.Extensions.AI — exposes
ICalendarStore as Microsoft.Extensions.AI tools with per-operation allow-listing (Read / Create / Update / Delete). Generates list_calendars, search_events, get_event, create_event, update_event, delete_event. AOT-compatible. See AI Tools.Chore
Recurrence is surfaced read-only; on Apple, attendee writes are ignored (EventKit limitation).
FixMac Catalyst
Document the
com.apple.security.personal-information.calendars sandbox entitlement, and add it to the MAUI sample. Mac Catalyst enables the App Sandbox by default, so without it RequestAccess returned Denied and no prompt ever appeared. See Permissions.Feature
DeleteEvent gained a deleteSeries flag — DeleteEvent(string eventId, bool deleteSeries = false, CancellationToken ct = default). For a recurring event, false removes only that occurrence and true removes it and all future ones; it is ignored for non-recurring events. Previously every delete was hardcoded to the single occurrence on Apple and to the whole series on Android. The delete_event AI tool takes the flag too. See Deleting a Recurring Event.Fix
Calendar pills in the MAUI sample’s calendar list are now selectable and actually filter the event list — they were previously non-interactive, with no
SelectionMode, no selection binding, and no filter state in the view model.

