dotnet/wpf · error · NullReferenceException

dpiInfo cannot be null

Error message

dpiInfo cannot be null

What it means

VisualTreeHelper.SetRootDpi throws NullReferenceException when the dpiInfo parameter is null. The method needs the DpiScale to propagate to the visual subtree and cannot proceed without it. (The null check pattern (object)dpiInfo == null throws NRE rather than ArgumentNullException, matching the original WPF source.)

Solutions

  1. Ensure a valid DpiScale is computed (e.g. from VisualTreeHelper.GetDpi(visual) or the source's DpiChanged event args) before calling
  2. Guard the call: if (dpiInfo == null) return or substitute a fallback DpiScale
  3. Verify the calling code passes the NewDpi/OldDpi property from DpiChangedEventArgs, not a nullable that can be null

Example fix

// before
visualTreeHelper.SetRootDpi(rootVisual, maybeDpi); // maybeDpi is null -> throws
// after
if (maybeDpi != null) VisualTreeHelper.SetRootDpi(rootVisual, maybeDpi.Value);
Defensive patterns

Strategy: validation

Validate before calling

if (dpiInfo == null)
    throw new ArgumentNullException(nameof(dpiInfo)); // fail fast at your boundary

Type guard

bool IsValidDpi(DpiScale? dpi) => dpi.HasValue && dpi.Value.PixelsPerInchX > 0 && dpi.Value.PixelsPerInchY > 0;

Try / catch

try { VisualTreeHelper.SetRootDpi(root, dpi); }
catch (NullReferenceException) { /* substitute default DPI, e.g. VisualTreeHelper.GetDpi(root) */ }

Prevention

When it happens

Trigger: Calling VisualTreeHelper.SetRootDpi(visual, null) — e.g. when a DPI-changed handler passes a default(DpiScale) struct boxed as null, or a variable that was never assigned.

Common situations: Top-level HwndSource/window DPI-change plumbing where DpiScale came from a nullable wrapper that was null; automation/tests invoking SetRootDpi directly without computing a valid DpiScale.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/0ef6143ab8dc5dc7. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/VisualTreeHelper.cs:106

        }

        /// <summary>
        /// Returns the DPI information at which this Visual is measured and rendered.
        /// </summary>
        public static DpiScale GetDpi(Visual visual)
        {
            return visual.GetDpi();
        }


        /// <summary>
        /// This method updates the DPI information of a visual. It can only be called on a Visual with no parent.
        /// </summary>
        public static void SetRootDpi(Visual visual, DpiScale dpiInfo)
        {
            if ((object)dpiInfo == null)
            {
                throw new NullReferenceException("dpiInfo cannot be null");
            }
            if (visual.InternalVisualParent != null)
            {
                throw new InvalidOperationException("UpdateDPI should only be called on the root of a Visual tree");
            }
            DpiFlags dpiFlags = DpiUtil.UpdateDpiScalesAndGetIndex(dpiInfo.PixelsPerInchX, dpiInfo.PixelsPerInchY);
            visual.RecursiveSetDpiScaleVisualFlags(new DpiRecursiveChangeArgs(dpiFlags, visual.GetDpi(), dpiInfo));
        }

        /// <summary>
        /// Visual parent of this Visual.
        /// </summary>
        public static DependencyObject GetParent(DependencyObject reference)
        {
            Visual visual;
            Visual3D visual3D;

            VisualTreeUtils.AsNonNullVisual(reference, out visual, out visual3D);

View on GitHub (pinned to 81131a70a4)