dotnet/wpf · error · InvalidOperationException

SR.RemovingPlaceholder

Error message

SR.RemovingPlaceholder

What it means

RemoveImpl throws InvalidOperationException with the RemovingPlaceholder message when the caller attempts to remove the CollectionView.NewItemPlaceholder item. The placeholder is a virtual marker row (shown when NewItemPlaceholderPosition is set), not a real item in the collection, so it can never be removed.

Solutions

  1. Check for CollectionView.NewItemPlaceholder and skip it before calling Remove/RemoveAt.
  2. Enumerate the underlying collection instead of the view when doing bulk removals, so the placeholder never appears.
  3. In DataGrid delete handlers, guard: if (view.IndexOf(item) is the placeholder or item == CollectionView.NewItemPlaceholder) return.
  4. Disable delete UI for the placeholder row via a row style/validation.

Example fix

// before
view.Remove(selectedItem);

// after
if (!Equals(selectedItem, CollectionView.NewItemPlaceholder))
    view.Remove(selectedItem);
Defensive patterns

Strategy: type-guard

Validate before calling

// C#
if (Equals(item, CollectionView.NewItemPlaceholder)) return; // skip

Type guard

bool IsPlaceholder(object item) => Equals(item, CollectionView.NewItemPlaceholder);

Try / catch

try { view.Remove(item); }
catch (InvalidOperationException ex) when (ex.Message.Contains("placeholder")) { /* skip placeholder */ }

Prevention

When it happens

Trigger: Calling Remove(CollectionView.NewItemPlaceholder) or RemoveAt(indexOfPlaceholder) — commonly when code enumerates the view and tries to delete 'all visible rows' including the placeholder row, or a user deletes the placeholder row in a grid.

Common situations: DataGrid bound to a view with NewItemPlaceholderPosition.AtBeginning/AtEnd and a delete handler acting on the selected item without checking for the placeholder; clearing loops that iterate the view's items directly.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs:897

        /// Remove the given item from the underlying collection.
        /// </summary>
        public void Remove(object item)
        {
            if (IsEditingItem || IsAddingNew)
                throw new InvalidOperationException(SR.Format(SR.MemberNotAllowedDuringAddOrEdit, "Remove"));
            VerifyRefreshNotDeferred();

            int index = InternalIndexOf(item);
            if (index >= 0)
            {
                RemoveImpl(item, index);
            }
        }

        private void RemoveImpl(object item, int index)
        {
            if (item == CollectionView.NewItemPlaceholder)
                throw new InvalidOperationException(SR.RemovingPlaceholder);

            BindingOperations.AccessCollection(InternalList,
                () =>
                {
                    ProcessPendingChanges();

                    // the pending changes may have moved (or even removed) the
                    // item.   Verify the index.
                    if (index >= InternalList.Count || !System.Windows.Controls.ItemsControl.EqualsEx(item, GetItemAt(index)))
                    {
                        index = InternalList.IndexOf(item);
                        if (index < 0)
                            return;
                    }

                    // convert the index from "view-relative" to "list-relative"
                    if (_isGrouping)
                    {

View on GitHub (pinned to 81131a70a4)