Runtime and lifecycle
Use the UI thread
Assign content and image properties, issue turn commands and refresh snapshots on the MAUI UI thread. Core geometry and interaction have no UI dependencies; the MAUI adapter and its dispatcher do.
Turn commands return false while a turn is active or the control is
disconnected. A rejected command preserves the current curl. New pointer
presses during settling leave the pending completion intact.
Own images deliberately
PageTurnView borrows images. Your application must keep them alive until they
are no longer assigned or used by an active turn.
PageCurlView and PageSpreadView own their captured textures. They reject and
dispose obsolete captures, retain a last-good frame on failure, and keep active
turn textures stable until the turn ends. Supplied destination images on
PageCurlView remain caller-owned. Your application also owns resources used by
hosted MAUI views, such as media players.
Handle cancellation and reuse
Before removing or recycling a view, detach or guard callbacks that can restart
turns so they ignore an inactive page. Then call CancelInteraction(), clear
borrowed image references and dispose images that no view still uses.
Cancellation rolls back, stops settling and releases pointer ownership.
Handler teardown cancels active work and releases adapter-owned snapshots.
For spreads, a cancelled caller wait does not mean the serialized capture has
finished cleaning up.
Also cancel active turns when your window stops. The demo subscribes to window stop/resume while its page is visible: it rolls back the turn, pauses video, and resumes video only if that scene remains selected. Removing the page detaches those handlers before releasing its content.
A spread refresh also waits for replacement content to attach and finish layout. Cancellation can stop the caller's wait; hiding, replacing content or disconnecting the handler releases obsolete layout waits. Keep refresh calls asynchronous so the UI thread can finish arranging the views.
The controls reject delayed results from hidden, replaced or disconnected
content. A live-page refresh waiting for a turn also becomes obsolete when its
content is hidden or replaced, so it cannot recapture the outgoing scene.
If you supply a custom snapshotter, use the UI thread, honor cancellation and
ensure each request eventually completes. Return an independently owned
SKImage for each successful capture. Transfer ownership to the control; do
not return an image shared with your cache or another capture.
Load and layout changes request automatic captures. Use
RefreshSnapshotAsync() for in-place edits; it waits for native layout and active
interaction to finish. Hiding or disconnecting a presentation ends its existing
layout waits.
An idle PageTurnView requests a fresh paint when it becomes visible, including
when the assigned images are unchanged. Rendering remains on demand.
Commit once
PageTurnCompleted reports direction and whether the turn committed. Advance
the model only when Committed is true. Threshold-crossing events provide
feedback; they do not change the current page.
A completion subscriber may start another turn on a connected control, including after cancellation. Disconnecting a wrapper rejects such restart requests before releasing its snapshots.
The sample routes gestures, buttons, reduced motion and haptics through this same completion path. Handle failed snapshots separately from successful navigation so the interface does not report a refresh that never happened.