Runtime And Updates
MountAsync
MountAsync walks the element tree, allocates NodeHandle values, writes
CreateElement, attributes, styles, text, listeners, and the final SetRoot
opcode, then sends the frame to the WebKitGTK renderer.
await using var host = RenderHostFactory.CreateWebKitGtk();
var app = App.Create(host);
var root = new Div();
root.Children.Add(new Button("Save"));
await app.MountAsync(root, cancellationToken);
await host.RunAsync(cancellationToken);
Update
Update and UpdateAsync submit imperative DOM update transactions. A
transaction reuses mounted element handles and writes text, attribute, style,
child, or listener changes into one frame.
await app.UpdateAsync(tx => tx
.SetText(button, "Saved")
.SetAttr(button, "class", "primary")
.SetStyle(button, StylePropId.FontSize, 16), cancellationToken);
HTML / CSS Load
The WebKitGTK host can load HTML and CSS directly:
await using var host = RenderHostFactory.CreateWebKitGtk();
await host.LoadHtmlAsync("<main><h1>Hello</h1></main>");
await host.LoadCssAsync("h1 { color: rgb(1, 2, 3); }");
LoadHtmlAsync does not allow JavaScript from the HTML by default. Before
insertion, the browser DOM parser parses the document and strips <script>,
iframe, object, embed, meta[http-equiv], inline event handlers,
srcdoc, and javascript: URLs, then replaces the current document head/body.
The framework shim remains available.
LoadCssAsync(css) writes the default stylesheet. LoadCssAsync(css, styleId)
writes or replaces a named stylesheet, which is useful for themes and hot style
updates.
Child transactions can create new subtrees, insert, move, detach, and destroy nodes:
var item = new Li("New");
app.Update(tx => tx
.InsertBefore(list, item, before)
.MoveBefore(list, item, null)
.RemoveChild(list, oldItem)
.RemoveNode(item));
RemoveChild only detaches the subtree from its parent, so the node handle can
be inserted again later. RemoveNode destroys the renderer node, releases the
arena rows, and clears listener bindings for that subtree.
Event Listeners
Listeners are mapped to wire tokens through ListenerRegistry. The renderer
only sends the token and event payload back; C# confirms the binding by token,
event id, and node id before parsing the payload and invoking the matching
delegate.
Action handler = () => Console.WriteLine("clicked");
app.Update(tx => tx.AddListener(button, eventId: 1, handler));
app.Update(tx => tx.RemoveListener(button, eventId: 1, handler));
RemoveListener requires the same delegate identity that was previously
registered. Removing an unknown listener throws instead of sending a meaningless
token to the renderer.
The same delegate can be bound to multiple nodes. Removing the listener from one
node does not affect the remaining node bindings. Destroying a node or disposing
the app clears the C# registry binding; the renderer shim also clears its
listener table when RemoveNode is applied.
Dispose
UltimateUiApp implements IAsyncDisposable. Disposal removes inbound event
subscriptions, clears the listener registry, and disposes the bound
IRenderHost or IDomBackend.