stride3d/stride · error · ArgumentNullException

Value cannot be null. (Parameter 'canvas')

Error message

Value cannot be null. (Parameter 'canvas')

What it means

The CanvasRenderer constructor requires a non-null Canvas and throws ArgumentNullException(nameof(canvas)) when null. CanvasRenderer wraps a WPF Canvas as the target of drawing commands (IDrawableRenderer); without a canvas nothing can be rendered, so the library fails fast at construction.

Solutions

  1. Ensure the Canvas is initialized (after InitializeComponent / Loaded) before constructing CanvasRenderer.
  2. Null-check the canvas at the construction site and defer renderer creation until the canvas is available.
  3. If the canvas is looked up by name, verify the x:Name matches and the element is in the visual/logical tree.
  4. Use lazy creation: create the renderer on first draw call, when the canvas is guaranteed to exist.

Example fix

// before
public MyControl()
{
    InitializeComponent();
    renderer = new CanvasRenderer(canvas); // canvas may be null if lookup failed
}
// after
public MyControl()
{
    InitializeComponent();
}
protected override void OnLoaded(EventArgs e)
{
    base.OnLoaded(e);
    if (canvas == null) throw new InvalidOperationException("Canvas not found.");
    renderer = new CanvasRenderer(canvas);
}
Defensive patterns

Strategy: validation

Validate before calling

if (canvas == null) throw new InvalidOperationException("Canvas must be resolved before creating CanvasRenderer.");

Type guard

static bool CanCreateRenderer(Canvas c) => c is not null;

Try / catch

try { renderer = new CanvasRenderer(canvas); }
catch (ArgumentNullException ex) when (ex.ParamName == "canvas") { log.Error("Canvas was null at renderer creation"); }

Prevention

When it happens

Trigger: Constructing CanvasRenderer with a null canvas — e.g. a Canvas field/property not yet assigned (XAML not yet loaded), a FindName/FindResource lookup returning null, or passing a null from a factory or data-binding that resolved before the visual tree was built.

Common situations: Instantiating the renderer in a control's constructor before InitializeComponent populated the canvas; code-behind using FindName with a mismatched x:Name; MVVM scenarios where the renderer is created before the view's visual tree exists.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/55999d2e3672645c. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Drawing/CanvasRenderer.cs:61

namespace Stride.Core.Presentation.Drawing
{
    using Color = Stride.Core.Mathematics.Color;

    public class CanvasRenderer : IDrawingContext
    {
        private readonly Dictionary<Color, Brush> cachedBrushes = new Dictionary<Color, Brush>();
        private const int MaxPolylinesPerLine = 64;
        private const int MinPointsPerPolyline = 16;

        /// <summary>
        /// The clip rectangle.
        /// </summary>
        private Rect? clip;

        public CanvasRenderer([NotNull] Canvas canvas)
        {
            if (canvas == null) throw new ArgumentNullException(nameof(canvas));
            Canvas = canvas;
            UseStreamGeometry = true;
        }

        /// <summary>
        /// Gets or sets the thickness limit for "balanced" line drawing.
        /// </summary>
        public double BalancedLineDrawingThicknessLimit { get; set; } = 3.5;

        [NotNull]
        public Canvas Canvas { get; }

        /// <summary>
        /// Gets or sets a value indicating whether to use stream geometry for lines and polygons rendering.
        /// </summary>
        /// <value><c>true</c> if stream geometry should be used; otherwise, <c>false</c> .</value>
        /// <remarks>Using stream geometry seems to be slightly faster than using path geometry.</remarks>
        public bool UseStreamGeometry { get; set; }

View on GitHub (pinned to 96fad776d2)