Table of Contents

Class DirectCanvasRenderer

Namespace
FlowGraph.Avalonia.Rendering
Assembly
FlowGraph.Avalonia.dll

A high-performance graph renderer that draws directly to a DrawingContext, bypassing the Avalonia visual tree for nodes and edges. This is optimized for large graphs (500+ nodes) where per-element Controls are too slow.

Uses GraphRenderModel for all geometry calculations to ensure 100% visual parity with the normal VisualTree renderer.

public class DirectCanvasRenderer : Control, INotifyPropertyChanged, IDataContextProvider, ILogical, IThemeVariantHost, IResourceHost, IResourceNode, IStyleHost, ISetLogicalParent, ISetInheritanceParent, ISupportInitialize, IStyleable, INamed, IInputElement, IDataTemplateHost, ISetterValue, IRenderLayer
Inheritance
AvaloniaObject
Animatable
StyledElement
Visual
Layoutable
Interactive
InputElement
Control
DirectCanvasRenderer
Implements
IDataContextProvider
ILogical
IThemeVariantHost
IResourceHost
IResourceNode
IStyleHost
ISetLogicalParent
ISetInheritanceParent
IStyleable
INamed
IInputElement
IDataTemplateHost
ISetterValue
Inherited Members
Control.FocusAdornerProperty
Control.TagProperty
Control.ContextMenuProperty
Control.ContextFlyoutProperty
Control.RequestBringIntoViewEvent
Control.ContextRequestedEvent
Control.LoadedEvent
Control.UnloadedEvent
Control.SizeChangedEvent
Control.GetTemplateFocusTarget()
Control.OnLoaded(RoutedEventArgs)
Control.OnUnloaded(RoutedEventArgs)
Control.OnSizeChanged(SizeChangedEventArgs)
Control.OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs)
Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs)
Control.OnGotFocus(GotFocusEventArgs)
Control.OnLostFocus(RoutedEventArgs)
Control.OnCreateAutomationPeer()
Control.OnPointerReleased(PointerReleasedEventArgs)
Control.OnKeyUp(KeyEventArgs)
Control.OnPropertyChanged(AvaloniaPropertyChangedEventArgs)
Control.FocusAdorner
Control.DataTemplates
Control.ContextMenu
Control.ContextFlyout
Control.IsLoaded
Control.Tag
Control.ContextRequested
Control.Loaded
Control.Unloaded
Control.SizeChanged
InputElement.FocusableProperty
InputElement.IsEnabledProperty
InputElement.IsEffectivelyEnabledProperty
InputElement.CursorProperty
InputElement.IsKeyboardFocusWithinProperty
InputElement.IsFocusedProperty
InputElement.IsHitTestVisibleProperty
InputElement.IsPointerOverProperty
InputElement.IsTabStopProperty
InputElement.GotFocusEvent
InputElement.LostFocusEvent
InputElement.KeyDownEvent
InputElement.KeyUpEvent
InputElement.TabIndexProperty
InputElement.TextInputEvent
InputElement.TextInputMethodClientRequestedEvent
InputElement.PointerEnteredEvent
InputElement.PointerExitedEvent
InputElement.PointerMovedEvent
InputElement.PointerPressedEvent
InputElement.PointerReleasedEvent
InputElement.PointerCaptureLostEvent
InputElement.PointerWheelChangedEvent
InputElement.TappedEvent
InputElement.HoldingEvent
InputElement.DoubleTappedEvent
InputElement.Focus(NavigationMethod, KeyModifiers)
InputElement.OnAccessKey(RoutedEventArgs)
InputElement.OnKeyDown(KeyEventArgs)
InputElement.OnTextInput(TextInputEventArgs)
InputElement.OnPointerEntered(PointerEventArgs)
InputElement.OnPointerExited(PointerEventArgs)
InputElement.OnPointerMoved(PointerEventArgs)
InputElement.OnPointerPressed(PointerPressedEventArgs)
InputElement.OnPointerCaptureLost(PointerCaptureLostEventArgs)
InputElement.OnPointerWheelChanged(PointerWheelEventArgs)
InputElement.UpdateIsEffectivelyEnabled()
InputElement.Focusable
InputElement.IsEnabled
InputElement.Cursor
InputElement.IsKeyboardFocusWithin
InputElement.IsFocused
InputElement.IsHitTestVisible
InputElement.IsPointerOver
InputElement.IsTabStop
InputElement.IsEffectivelyEnabled
InputElement.TabIndex
InputElement.KeyBindings
InputElement.IsEnabledCore
InputElement.GestureRecognizers
InputElement.GotFocus
InputElement.LostFocus
InputElement.KeyDown
InputElement.KeyUp
InputElement.TextInput
InputElement.TextInputMethodClientRequested
InputElement.PointerEntered
InputElement.PointerExited
InputElement.PointerMoved
InputElement.PointerPressed
InputElement.PointerReleased
InputElement.PointerCaptureLost
InputElement.PointerWheelChanged
InputElement.Tapped
InputElement.Holding
InputElement.DoubleTapped
Interactive.RaiseEvent(RoutedEventArgs)
Interactive.BuildEventRoute(RoutedEvent)
Layoutable.DesiredSizeProperty
Layoutable.WidthProperty
Layoutable.HeightProperty
Layoutable.MinWidthProperty
Layoutable.MaxWidthProperty
Layoutable.MinHeightProperty
Layoutable.MaxHeightProperty
Layoutable.MarginProperty
Layoutable.HorizontalAlignmentProperty
Layoutable.VerticalAlignmentProperty
Layoutable.UseLayoutRoundingProperty
Layoutable.UpdateLayout()
Layoutable.ApplyTemplate()
Layoutable.Measure(Size)
Layoutable.Arrange(Rect)
Layoutable.InvalidateMeasure()
Layoutable.InvalidateArrange()
Layoutable.AffectsMeasure<T>(params AvaloniaProperty[])
Layoutable.AffectsArrange<T>(params AvaloniaProperty[])
Layoutable.MeasureCore(Size)
Layoutable.MeasureOverride(Size)
Layoutable.ArrangeCore(Rect)
Layoutable.ArrangeOverride(Size)
Layoutable.OnMeasureInvalidated()
Layoutable.OnVisualParentChanged(Visual, Visual)
Layoutable.Width
Layoutable.Height
Layoutable.MinWidth
Layoutable.MaxWidth
Layoutable.MinHeight
Layoutable.MaxHeight
Layoutable.Margin
Layoutable.HorizontalAlignment
Layoutable.VerticalAlignment
Layoutable.DesiredSize
Layoutable.IsMeasureValid
Layoutable.IsArrangeValid
Layoutable.UseLayoutRounding
Layoutable.EffectiveViewportChanged
Layoutable.LayoutUpdated
Visual.BoundsProperty
Visual.ClipToBoundsProperty
Visual.ClipProperty
Visual.IsVisibleProperty
Visual.OpacityProperty
Visual.OpacityMaskProperty
Visual.EffectProperty
Visual.HasMirrorTransformProperty
Visual.RenderTransformProperty
Visual.RenderTransformOriginProperty
Visual.FlowDirectionProperty
Visual.VisualParentProperty
Visual.ZIndexProperty
Visual.GetFlowDirection(Visual)
Visual.SetFlowDirection(Visual, FlowDirection)
Visual.InvalidateVisual()
Visual.AffectsRender<T>(params AvaloniaProperty[])
Visual.OnAttachedToVisualTree(VisualTreeAttachmentEventArgs)
Visual.OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs)
Visual.InvalidateMirrorTransform()
Visual.Bounds
Visual.ClipToBounds
Visual.Clip
Visual.IsEffectivelyVisible
Visual.IsVisible
Visual.Opacity
Visual.OpacityMask
Visual.Effect
Visual.HasMirrorTransform
Visual.RenderTransform
Visual.RenderTransformOrigin
Visual.FlowDirection
Visual.ZIndex
Visual.VisualChildren
Visual.VisualRoot
Visual.BypassFlowDirectionPolicies
Visual.AttachedToVisualTree
Visual.DetachedFromVisualTree
StyledElement.DataContextProperty
StyledElement.NameProperty
StyledElement.ParentProperty
StyledElement.TemplatedParentProperty
StyledElement.ThemeProperty
StyledElement.BeginInit()
StyledElement.EndInit()
StyledElement.ApplyStyling()
StyledElement.InitializeIfNeeded()
StyledElement.OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs)
StyledElement.OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs)
StyledElement.OnDataContextBeginUpdate()
StyledElement.OnDataContextEndUpdate()
StyledElement.OnInitialized()
StyledElement.Name
StyledElement.Classes
StyledElement.DataContext
StyledElement.IsInitialized
StyledElement.Styles
StyledElement.StyleKey
StyledElement.Resources
StyledElement.TemplatedParent
StyledElement.Theme
StyledElement.LogicalChildren
StyledElement.PseudoClasses
StyledElement.StyleKeyOverride
StyledElement.Parent
StyledElement.ActualThemeVariant
StyledElement.AttachedToLogicalTree
StyledElement.DetachedFromLogicalTree
StyledElement.DataContextChanged
StyledElement.Initialized
StyledElement.ResourcesChanged
StyledElement.ActualThemeVariantChanged
Animatable.TransitionsProperty
Animatable.OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs)
Animatable.Transitions
AvaloniaObject.CheckAccess()
AvaloniaObject.VerifyAccess()
AvaloniaObject.ClearValue(AvaloniaProperty)
AvaloniaObject.ClearValue<T>(AvaloniaProperty<T>)
AvaloniaObject.ClearValue<T>(StyledProperty<T>)
AvaloniaObject.ClearValue<T>(DirectPropertyBase<T>)
AvaloniaObject.GetHashCode()
AvaloniaObject.GetValue(AvaloniaProperty)
AvaloniaObject.GetValue<T>(StyledProperty<T>)
AvaloniaObject.GetValue<T>(DirectPropertyBase<T>)
AvaloniaObject.GetBaseValue<T>(StyledProperty<T>)
AvaloniaObject.IsAnimating(AvaloniaProperty)
AvaloniaObject.IsSet(AvaloniaProperty)
AvaloniaObject.SetValue<T>(StyledProperty<T>, T, BindingPriority)
AvaloniaObject.SetValue<T>(DirectPropertyBase<T>, T)
AvaloniaObject.SetCurrentValue<T>(StyledProperty<T>, T)
AvaloniaObject.Bind(AvaloniaProperty, IBinding)
AvaloniaObject.CoerceValue(AvaloniaProperty)
AvaloniaObject.RaisePropertyChanged<T>(DirectPropertyBase<T>, T, T)
AvaloniaObject.SetAndRaise<T>(DirectPropertyBase<T>, ref T, T)
AvaloniaObject.InheritanceParent
AvaloniaObject.this[AvaloniaProperty]
AvaloniaObject.this[IndexerDescriptor]
AvaloniaObject.PropertyChanged

Remarks

DirectCanvasRenderer supports custom node rendering via the IDirectNodeRenderer interface. When a node's renderer implements IDirectNodeRenderer, it delegates drawing to that implementation.

Edge endpoint handles are rendered when ShowEdgeEndpointHandles is true and an edge is selected, allowing reconnection/disconnection.

Transform Mode: This renderer uses SelfTransformed mode. It performs its own coordinate transforms internally and MUST be placed in an untransformed container (e.g., RootPanel, not MainCanvas) to avoid double-transformation.

Constructors

DirectCanvasRenderer(FlowCanvasSettings)

Creates a new DirectCanvasRenderer with the specified settings.

public DirectCanvasRenderer(FlowCanvasSettings settings)

Parameters

settings FlowCanvasSettings

Canvas settings for rendering configuration.

DirectCanvasRenderer(FlowCanvasSettings, NodeRendererRegistry?)

Creates a new DirectCanvasRenderer with the specified settings and node renderer registry.

public DirectCanvasRenderer(FlowCanvasSettings settings, NodeRendererRegistry? nodeRenderers)

Parameters

settings FlowCanvasSettings

Canvas settings for rendering configuration.

nodeRenderers NodeRendererRegistry

Optional registry of custom node renderers.

Properties

DisplayName

Display name for debugging and UI purposes.

public string DisplayName { get; }

Property Value

string

EditingEdgeId

Gets the ID of the edge currently being edited, or null if no edge is being edited.

public string? EditingEdgeId { get; }

Property Value

string

EditingNodeId

Gets the ID of the node currently being edited, or null if no node is being edited.

public string? EditingNodeId { get; }

Property Value

string

IsEditing

Gets whether inline editing is currently active.

public bool IsEditing { get; }

Property Value

bool

LayerId

Unique identifier for this layer.

public string LayerId { get; }

Property Value

string

Model

Gets the render model used for geometry calculations. This model is shared with other renderers to ensure visual parity.

public CanvasRenderModel Model { get; }

Property Value

CanvasRenderModel

NodeRenderers

Gets or sets the node renderer registry for custom node types.

public NodeRendererRegistry? NodeRenderers { get; set; }

Property Value

NodeRendererRegistry

TransformMode

How this layer participates in viewport transformations.

public LayerTransformMode TransformMode { get; }

Property Value

LayerTransformMode

Remarks

DirectCanvasRenderer uses SelfTransformed because it performs its own coordinate transforms internally via ScreenToCanvas(double, double). It MUST be placed outside any transformed container (e.g., as a child of RootPanel, not MainCanvas) to avoid double-transformation bugs.

Methods

BeginEditEdge(string)

Begins editing an edge's label. The label will not be drawn while editing.

public void BeginEditEdge(string edgeId)

Parameters

edgeId string

ID of the edge to edit.

BeginEditNode(string)

Begins editing a node's label. The label will not be drawn while editing.

public void BeginEditNode(string nodeId)

Parameters

nodeId string

ID of the node to edit.

ClearHoveredEndpointHandle()

Clears the hovered endpoint handle state.

public void ClearHoveredEndpointHandle()

ClearHoveredPort()

Clears the hovered port state.

public void ClearHoveredPort()

EndEditEdge()

Ends editing an edge's label.

public void EndEditEdge()

EndEditNode()

Ends editing a node's label.

public void EndEditNode()

GetEdgeEndpointViewportPosition(Edge, bool)

Gets the viewport position for an edge endpoint (source or target).

public Point GetEdgeEndpointViewportPosition(Edge edge, bool isSource)

Parameters

edge Edge
isSource bool

Returns

Point

GetPortScreenPosition(Node, Port, bool)

Gets the screen position for a port.

[Obsolete("Use GetPortViewportPosition or GetPortCanvasPosition instead.")]
public Point GetPortScreenPosition(Node node, Port port, bool isOutput)

Parameters

node Node
port Port
isOutput bool

Returns

Point

GetPortViewportPosition(Node, Port, bool)

Gets the viewport position for a port.

public Point GetPortViewportPosition(Node node, Port port, bool isOutput)

Parameters

node Node
port Port
isOutput bool

Returns

Point

Remarks

WARNING: For distance calculations with pointer events, prefer using canvas coordinates (via _model.GetPortPosition) since pointer events give canvas coords via e.GetPosition(MainCanvas).

HitTestEdge(double, double)

Performs hit testing to find an edge at the given screen coordinates.

public Edge? HitTestEdge(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

Edge

The hit edge, or null if no edge was hit.

HitTestEdgeEndpointHandle(double, double)

Performs hit testing to find an edge endpoint handle at the given screen coordinates.

public (Edge edge, bool isSource)? HitTestEdgeEndpointHandle(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

(Edge edge, bool isSource)?

Tuple of (edge, isSource) or null if no handle hit.

HitTestNode(double, double)

Performs hit testing to find a node at the given screen coordinates. Uses quadtree for O(log N) spatial query instead of linear scan.

public Node? HitTestNode(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

Node

The hit node, or null if no node was hit.

HitTestPort(double, double)

Performs hit testing to find a port at the given screen coordinates. Uses quadtree range query for O(log N) spatial lookup.

public (Node node, Port port, bool isOutput)? HitTestPort(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

(Node node, Port port, bool isOutput)?

Tuple of (node, port, isOutput) or null if no port hit.

HitTestResizeHandle(double, double)

Performs hit testing to find a resize handle at the given screen coordinates.

public (Node node, ResizeHandlePosition position)? HitTestResizeHandle(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

(Node node, ResizeHandlePosition position)?

Tuple of (node, position) or null if no handle hit.

HitTestShape(double, double)

Hit tests for shapes at the given screen coordinates. Shapes with higher ZIndex are tested first (topmost shapes have priority).

public ShapeElement? HitTestShape(double screenX, double screenY)

Parameters

screenX double

Screen X coordinate.

screenY double

Screen Y coordinate.

Returns

ShapeElement

The hit shape, or null if no shape was hit.

HitTestShapeResizeHandle(double, double)

Performs hit testing to find a shape resize handle at the given screen coordinates. Shape resize handles are shown when a shape is selected and resizable.

public (ShapeElement shape, ResizeHandlePosition position)? HitTestShapeResizeHandle(double screenX, double screenY)

Parameters

screenX double

X coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

screenY double

Y coordinate relative to the root panel (not canvas). Will be converted internally via ScreenToCanvas.

Returns

(ShapeElement shape, ResizeHandlePosition position)?

Tuple of (shape, position) or null if no handle hit.

InvalidateIndex()

Marks the spatial index as dirty, forcing rebuild on next hit test. Call this when nodes are added, removed, or moved.

public void InvalidateIndex()

InvalidatePositions()

Marks the spatial index as dirty due to node position changes. Unlike InvalidateIndex(), this preserves the node lookup dictionary since the nodes themselves haven't changed, only their positions. Call this during dragging operations for better performance.

public void InvalidatePositions()

Render(DrawingContext)

Renders the visual to a Avalonia.Media.DrawingContext.

public override void Render(DrawingContext context)

Parameters

context DrawingContext

The drawing context.

SetHoveredEndpointHandle(string?, bool)

Sets the currently hovered edge endpoint handle for visual feedback.

public void SetHoveredEndpointHandle(string? edgeId, bool isSource)

Parameters

edgeId string

ID of the edge, or null to clear.

isSource bool

True if hovering the source handle, false for target.

SetHoveredPort(string?, string?)

Sets the currently hovered port for visual feedback.

public void SetHoveredPort(string? nodeId, string? portId)

Parameters

nodeId string

ID of the node containing the port, or null to clear.

portId string

ID of the port, or null to clear.

Update(Graph?, ViewportState, ThemeResources)

Updates the renderer with the current graph state and triggers a redraw.

public void Update(Graph? graph, ViewportState viewport, ThemeResources theme)

Parameters

graph Graph

The graph to render.

viewport ViewportState

Current viewport state for zoom/pan.

theme ThemeResources

Theme resources for styling.

UpdateSettings(FlowCanvasSettings)

Updates the settings and propagates to the render model.

public void UpdateSettings(FlowCanvasSettings settings)

Parameters

settings FlowCanvasSettings

The new settings.