dotnet/wpf · error · ArgumentOutOfRangeException

SR.TableCollectionCountNeedNonNegNum

Error message

SR.TableCollectionCountNeedNonNegNum

What it means

Thrown by RowDefinitionCollection.RemoveRange when count is negative. A negative removal count is meaningless, so ArgumentOutOfRangeException with SR.TableCollectionCountNeedNonNegNum is thrown after the index check passes.

Solutions

  1. Compute count as Math.Max(0, targetCount - currentCount)
  2. Check count >= 0 before calling RemoveRange
  3. Use Math.Abs only if a positive count was truly intended

Example fix

// before
grid.RowDefinitions.RemoveRange(start, desiredRows - grid.RowDefinitions.Count);
// after
int removeCount = Math.Max(0, grid.RowDefinitions.Count - desiredRows);
grid.RowDefinitions.RemoveRange(grid.RowDefinitions.Count - removeCount, removeCount);
Defensive patterns

Strategy: validation

Validate before calling

if (count < 0) count = 0;
if (index >= 0 && index < grid.RowDefinitions.Count)
    grid.RowDefinitions.RemoveRange(index, Math.Min(count, grid.RowDefinitions.Count - index));

Prevention

When it happens

Trigger: Calling grid.RowDefinitions.RemoveRange(index, count) with count < 0, e.g. RemoveRange(0, desired - current) where desired < current, producing a negative delta.

Common situations: Computing the count as a difference of row targets without ordering the subtraction, subtracting header/footer offsets incorrectly, or integer arithmetic with sign errors.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinition.cs:304

        /// <summary>
        ///     Removes a range of RowDefinitions from the RowDefinitionCollection.
        /// </summary>
        /// <param name="index">
        ///     The zero-based index of the range of RowDefinitions to remove.
        /// </param>
        /// <param name="count">
        ///     The number of RowDefinitions to remove.
        /// </param>
        public void RemoveRange(int index, int count)
        {
            PrivateVerifyWriteAccess();
            if (index < 0 || index >= _size)
            {
                throw new ArgumentOutOfRangeException(SR.TableCollectionOutOfRange);
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(SR.TableCollectionCountNeedNonNegNum);
            }
            if (_size - index < count)
            {
                throw new ArgumentException(SR.TableCollectionRangeOutOfRange);
            }

            PrivateOnModified();

            if (count > 0)
            {
                for (int i = index + count - 1; i >= index; --i)
                {
                    Debug.Assert(   _items[i] != null
                                &&  _items[i].Parent == _owner );

                    PrivateDisconnectChild(_items[i]);
                }

View on GitHub (pinned to 81131a70a4)