Skip to content

Architecture

Nicolás Seijas edited this page Jul 28, 2026 · 2 revisions

Architecture

The primary rule

The core package has no knowledge of the UI framework.

The core package (Rambla, netstandard2.0) must not use Dispatcher, Application.Current, DispatcherPriority or any other type from WPF, WinUI or Avalonia. All movement to the UI thread goes through the IStateScheduler interface. This rule keeps Rambla usable with more than one UI framework.

Rambla             the core. It has no UI framework.
Rambla.Diagnostics measurement. It uses only the core.
Rambla.Wpf         DispatcherStateScheduler for WPF.
Rambla.Avalonia    DispatcherStateScheduler for Avalonia.
Rambla.WinUI       not available. Refer to the Roadmap.

The flow

Background thread writes a value
        |  SetField changes the field and marks the property
        v
The set of dirty properties  (Rambla arms one flush at a time)
        |  IStateScheduler.Post(flush)
        v
The UI thread  (immediately or later)
        |  One PropertyChanged for each dirty property
        v
The bindings

The parts

  • RamblaState — the base class. It has SetField, BeginUpdate(), Update(), MarkDirty() and the optional StateMetrics.
  • IStateScheduler — it moves a flush to the UI thread. The core has ImmediateStateScheduler, SynchronizationContextStateScheduler and ThrottlingStateScheduler. The adapter packages add one scheduler each.
  • RamblaList<T> and RamblaDictionary<TKey,TValue> — the collections. They use the same flush model.
  • AsyncStateCommand — an ICommand that holds the state of its run.
  • IStateProbe — an observer of the mutations and the flushes. The diagnostics package uses it. A probe does not change the behavior.
  • The source generatorsStateGenerator for [State] and StateCommandGenerator for [StateCommand]. Both are compile-time generators. They use no reflection.

How Rambla coalesces

RamblaState keeps a set of dirty properties. It arms one flush at a time. All the mutations between the arm operation and the flush go into that one flush. Thus many writes become one notification for each property.

The ThrottlingStateScheduler adds a limit in time. It releases a maximum of MaxRefreshRate flushes in one second.

The module map

Rambla
├── Core          RamblaState · StateMetrics · RamblaOptions
│                 StateAttribute · StateCommandAttribute · AsyncStateCommand
├── Collections   RamblaList<T> · RamblaDictionary<TKey,TValue>
├── Scheduling    IStateScheduler · ImmediateStateScheduler
│                 SynchronizationContextStateScheduler · ThrottlingStateScheduler
└── Probes        IStateProbe

Rambla.Generators  StateGenerator (RMB001-RMB005)
                   StateCommandGenerator (RMB006-RMB009)

Rambla.Diagnostics StateDiagnostics · DiagnosticsSession · DiagnosticsSnapshot
                   DiagnosticsScheduler · HotProperty · Recommendation

Rambla and the other libraries

Rambla is more simple than a reactive framework. It has mutable state, safe publication from any thread, coalesced notifications, batches and diagnostics. Use Rambla together with CommunityToolkit.Mvvm and ReactiveUI. Rambla is not a replacement for them.

Clone this wiki locally