dotnet/wpf · error · InvalidOperationException

SR.GenerationNotInProgress

Error message

SR.GenerationNotInProgress

What it means

IItemContainerGenerator.GenerateNext() throws InvalidOperationException when the generator has no active generation session. GenerateNext may only be called between StartAt and a call to GenerateNext/Remove that ends the session; when the internal _generator worker is null, the generator is not in progress. The library throws to prevent generating containers outside a valid generation lifecycle.

Solutions

  1. Call StartAt(generatorPosition, GeneratorDirection.Forward, true) before the first GenerateNext call.
  2. Track the session state: only call GenerateNext while your generation loop (between StartAt and RemoveAllInternal/Recycle) is active.
  3. Use ItemsControl/ItemContainerGenerator public APIs (GenerateChild, ContainerForIndex) instead of driving IItemContainerGenerator manually.

Example fix

// before
var container = generator.GenerateNext();

// after
var pos = new GeneratorPosition(-1, 0);
using (generator.StartAt(pos, GeneratorDirection.Forward, true))
{
    bool isNewlyRealized;
    var container = generator.GenerateNext(out isNewlyRealized);
    generator.PrepareItemContainer(container);
}
Defensive patterns

Strategy: validation

Validate before calling

// Track generation session state yourself
bool isGenerating = false;
generator.StartAt(new GeneratorPosition(-1, 0), GeneratorDirection.Forward, true);
isGenerating = true;
if (!isGenerating) throw new InvalidOperationException("Call StartAt first");
var c = generator.GenerateNext(out bool realized);

Type guard

bool CanGenerate(IItemContainerGenerator g, bool sessionStarted) => sessionStarted;

Prevention

When it happens

Trigger: Calling ((IItemContainerGenerator)itemsControl.ItemContainerGenerator).GenerateNext() without first calling StartAt (or after the generation session was ended, e.g. after Remove/Recycle or a completed pass).

Common situations: Custom panels or virtualizing controls that implement IItemContainerGenerator directly but forget to call StartAt; re-entrant calls during layout after the previous generation pass already closed the session.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:225

                throw new InvalidOperationException(SR.GenerationInProgress);

            _generator = new Generator(this, position, direction, allowStartAtRealizedItem);
            return _generator;
        }

        public IDisposable GenerateBatches()
        {
            if (_isGeneratingBatches)
                throw new InvalidOperationException(SR.GenerationInProgress);

            return new BatchGenerator(this);
        }

        DependencyObject IItemContainerGenerator.GenerateNext()
        {
            bool isNewlyRealized;
            if (_generator == null)
                throw new InvalidOperationException(SR.GenerationNotInProgress);

            return _generator.GenerateNext(true, out isNewlyRealized);
        }

        DependencyObject IItemContainerGenerator.GenerateNext(out bool isNewlyRealized)
        {
            if (_generator == null)
                throw new InvalidOperationException(SR.GenerationNotInProgress);

            return _generator.GenerateNext(false, out isNewlyRealized);
        }

        /// <summary>
        /// Prepare the given element to act as the container for the
        /// corresponding item.  This includes applying the container style,
        /// forwarding information from the host control (ItemTemplate, etc.),
        /// and other small adjustments.
        /// </summary>

View on GitHub (pinned to 81131a70a4)