1

I have business object class that contains definition of List<T> for other business objects.

I cannot change class structure, so I cannot simply use ObservableCollection<T> instead of List<T> but I want to leverage ObservableCollection<T> functionality. So I created a sort of a observable collection wrapper class like this (also tried it with IList<T> instead of ICollection<T>).

public class CollectionObservableOverlay<T> : ICollection<T>, INotifyCollectionChanged
{
    protected ICollection<T> _wrappedCollection;

    #region ICollection<T> properties
    public int Count { get { return _wrappedCollection.Count; } }

    public bool IsReadOnly { get { return _wrappedCollection.IsReadOnly; } }
    #endregion

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public CollectionObservableOverlay(ICollection<T> wrappedCollection)
    {
        _wrappedCollection = wrappedCollection;
    }

    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged?.Invoke(this, e);
    }

    #region ICollection<T> methods

    public void Add(T item)
    {
        _wrappedCollection.Add(item);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));

    }

    public void Clear()
    {
        _wrappedCollection.Clear();
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public bool Contains(T item)
    {
        return _wrappedCollection.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        CopyTo(array, arrayIndex);
    }

    public virtual bool Remove(T item)
    {
        bool removed = _wrappedCollection.Remove(item);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        return removed;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _wrappedCollection.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)_wrappedCollection).GetEnumerator();
    }
    #endregion
}

The problem is, when I bind instance of CollectionObservableOverlay to DataGrid as ItemsSource and try to edit items, i get the following error:

System.InvalidOperationException
  HResult=0x80131509
  Message='EditItem' is not allowed for this view.
  Source=PresentationFramework

I tried binding to underlying collection directly, and that works fine for DataGrid editing purposes, so underlying list or it's contained objects should not be the source of the problem.

My guess is that I am missing some functionalities which are implemented in concrete List<T> type, but are not present at IList<T> or ICollection<T> interfaces.

I read this, and other related questions and answers but none of them are providing solution on how to do this, or answer if it is even possible. As far as I understand, ICollectionView provided to DataGrid should implement IEditableCollectionView, but I don't know how to achieve that kind of behavior. Any help is welcome.

Miljac
  • 135
  • 1
  • 12

1 Answers1

1

Your source collection must implement the non-generic IList interface for the internal editing functionality of the DataGrid control to work as expected.

List<T> and ObservableCollection<T> do this but HashSet<T> doesn't for example.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • But my source collection is of type List as stated at the top of my question. And i also tried to use IList instead of ICollection for wrapper class, and it still doesn't work. – Miljac Oct 25 '18 at 05:13
  • 1
    @Miljac: No. `CollectionObservableOverlay` is not a `List`. And it doesn't implement the non-generic `IList` interface. Implementing the generic `IList` interface is not enough. – mm8 Oct 25 '18 at 14:44
  • I totally missed that non-generic part, I totally overlooked it altogether, thank you for pointing that out, It works now – Miljac Oct 26 '18 at 05:48