Skip to content

Interaction Services & Spatial Math

When building seamless UI interactions (like spatial cursor navigation between distinct text controls), it is critical to keep the UI math decoupled from the event triggers. Dumping complex coordinate translation directly into a View's code-behind or an Attached Behavior creates brittle, unmaintainable code.

To ensure complex UI logic is reproducible and factorized, implement a strict 3-Layer Architecture.

The 3-Layer Architecture

1. The Trigger (Attached Behaviors)

Purpose: Determines when an interaction occurs.

  • Lives in the Behaviors/ directory (e.g., EditorNavigation.cs).
  • Subscribes to input events (like KeyDown via RoutingStrategies.Tunnel to bypass control-internal event swallowing).
  • Contains no layout math. It simply detects the trigger (e.g., ArrowDown at caret line 1) and delegates to a service.

2. The Translator (UI Services)

Purpose: Calculates where the interaction resolves physically.

  • Lives in a static service class (e.g., Services/UI/SpatialNavigationService.cs).
  • Handles aligning the universes. If two controls have different margins or font sizes, coordinate X: 50 in one is not X: 50 in the other.
  • Uses Avalonia's Visual.TranslatePoint(Point, Visual) to perfectly map physical pixels from the source control's coordinate space into the target control's coordinate space.

3. The Control Adapters (The Glue)

Purpose: Abstracts away the unique hit-testing quirks of specific controls.

  • Lives in extension methods (e.g., Utils/TextBoxExtensions.cs).
  • Standard Avalonia TextBox and AvaloniaEdit:TextEditor calculate text physics completely differently.
  • Services should not know how to extract the caret Rect from a TextPresenter, nor should they know how to call editor.TextArea.TextView.GetPosition().
  • Adapters expose simple methods like GetCaretVisualX() and SetCaretFromVisualX(double x), allowing the Service to orchestrate the translation abstractly without tightly coupling to framework-specific rendering internals.