dotnet/maui · error · InvalidOperationException

ViewCell must have a View

Error message

ViewCell must have a View

What it means

Thrown by the iOS ViewCellRenderer.GetNewRenderer when ViewCell.View is null at render time. The iOS renderer, like its Android counterpart, requires a non-null child View to create a platform handler and layout the cell.

Source

Thrown at src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ViewCellRenderer.cs:175

					{
						viewCell.PropertyChanged -= ViewCellPropertyChanged;
						viewCell.View.MeasureInvalidated -= OnMeasureInvalidated;
						SetRealCell(viewCell, null);
					}
#pragma warning restore CS0618 // Type or member is obsolete
					_viewCell = null;
				}

				_disposed = true;

				base.Dispose(disposing);
			}

			IPlatformViewHandler GetNewRenderer()
			{
#pragma warning disable CS0618 // Type or member is obsolete
				if (ViewCell is not ViewCell viewCell || viewCell.View == null)
					throw new InvalidOperationException($"ViewCell must have a {nameof(viewCell.View)}");
#pragma warning restore CS0618 // Type or member is obsolete

				var newRenderer = viewCell.View.ToHandler(viewCell.View.FindMauiContext());
				_rendererRef = new WeakReference<IPlatformViewHandler>(newRenderer);
				ContentView.ClearSubviews();
				ContentView.AddSubview(newRenderer.VirtualView.ToPlatform());
				return (IPlatformViewHandler)newRenderer;
			}

#pragma warning disable CS0618 // Type or member is obsolete
			void UpdateCell(ViewCell cell)
#pragma warning restore CS0618 // Type or member is obsolete
			{
#pragma warning disable CS0618 // Type or member is obsolete
				if (ViewCell is ViewCell oldCell)
				{
					BeginInvokeOnMainThread(oldCell.SendDisappearing);
					oldCell.PropertyChanged -= ViewCellPropertyChanged;

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Always assign a non-null View synchronously in the DataTemplate factory / cell construction.
  2. Use a placeholder View and update it later if content loads asynchronously.
  3. Validate the cell has a View before it enters the list's measurement cycle.

Example fix

// before
listView.ItemTemplate = new DataTemplate(() => new ViewCell());

// after
listView.ItemTemplate = new DataTemplate(() =>
{
    return new ViewCell { View = new StackLayout { Children = { new Label { Text = "Loading" } } } };
});
Defensive patterns

Strategy: validation

Validate before calling

static ViewCell MakeCell() =>
    new ViewCell { View = new StackLayout { Children = { new Label { Text = "Loading" } } } };

Type guard

static bool HasView(ViewCell c) => c.View is not null;

Prevention

When it happens

Trigger: A ViewCell with no View child. View set to null during/after recycling. A DataTemplate returning a ViewCell whose View is populated asynchronously and not yet set when the renderer requests a new handler.

Common situations: Empty <ViewCell/> in a GroupHeaderTemplate or ItemTemplate. Lazy/async View population that has not completed by measure time. Conditional code that fails to assign View on some path.

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/fd65c393dd607bf7. Report an issue: GitHub.