xaml-csharp-development-skill-for-avalonia

Custom Drawing, Text, Shapes, and SkiaSharp

Table of Contents

  1. Scope and APIs
  2. Custom Drawing in Controls
  3. Custom Draw Operations
  4. Text Rendering APIs
  5. Shape Rendering APIs
  6. Working with SkiaSharp
  7. Best Practices
  8. Troubleshooting

Scope and APIs

Primary APIs:

Reference source files:

Custom Drawing in Controls

Use Render(DrawingContext context) for direct immediate-mode drawing:

public sealed class ChartSurface : Control
{
    public override void Render(DrawingContext context)
    {
        base.Render(context);

        context.DrawRectangle(Brushes.Black, null, new Rect(Bounds.Size));
        context.DrawLine(new Pen(Brushes.Lime, 2), new Point(0, Bounds.Height), new Point(Bounds.Width, 0));
    }
}

Custom Draw Operations

Use ICustomDrawOperation when you need backend-specific access (for example Skia lease features).

Pattern:

  1. Implement Bounds, HitTest, Render, and Dispose.
  2. In control render, call context.Custom(op).
public override void Render(DrawingContext context)
{
    context.Custom(new MyCustomDrawOp(new Rect(Bounds.Size)));
}

From the sample, inside custom op:

Text Rendering APIs

Use:

Typical flow for advanced text:

  1. Build TextLayout with typeface, size, wrapping, trimming.
  2. Read metrics (Width, Height, Baseline, etc.).
  3. Call TextLayout.Draw(context, origin).
  4. Use hit test methods when needed (HitTestTextPosition, ranges).

Shape Rendering APIs

Use built-in shape controls when possible:

Shape.Render ultimately draws geometry with DrawingContext.DrawGeometry.

Guidance:

Working with SkiaSharp

In-process Skia access during rendering

if (context.TryGetFeature<ISkiaSharpApiLeaseFeature>(out var leaseFeature))
{
    using var lease = leaseFeature.Lease();
    var canvas = lease.SkCanvas;
    // Skia drawing here
}

Render Avalonia visual to external SKCanvas

Use helper:

This is useful when rendering into non-Avalonia canvas hosts.

Best Practices

Troubleshooting

  1. Nothing is drawn:
    • Bounds may be zero.
    • Brush/pen is null for expected draw path.
    • Clipping or transform hides content.
  2. Custom draw op runs but no Skia feature:
    • Current backend/context is not exposing ISkiaSharpApiLeaseFeature.
    • Implement fallback path with ImmediateDrawingContext.
  3. Text appears blurry or mismeasured:
    • Mismatch in DPI assumptions or font setup.
    • Use TextLayout metrics and avoid ad-hoc baseline math.
  4. Frequent redraw causes jank:
    • Avoid unconditional per-frame InvalidateVisual without throttling.
    • Use request-frame scheduling APIs intentionally.

XAML-First and Code-Only Usage

Default mode:

XAML-first references:

XAML-first usage example:

<Grid xmlns="https://github.com/avaloniaui"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:MyApp.Controls">
  <Path Stroke="DodgerBlue"
        StrokeThickness="2"
        Data="M 10,10 L 110,10 110,60 Z" />

  <local:ChartSurface Width="320" Height="180" />
</Grid>

Code-only alternative (on request):

var surface = new ChartSurface
{
    Width = 320,
    Height = 180
};