DataGrid（WPF） の ItemsSource には IList が必要

最近ハマったので書き残しておきます。

結論は表題の通り、
###DataGrid のItemsSource にバインドするコレクションには、非ジェネリックの IList を実装する必要があります。###


***

横着して以下の様な自作コレクションを作って DataGrid にバインドした時のことです。

```c#:MyCollection.cs
    public class MyCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable
    {
        // ～ 略 ～
    }
```

セルを編集しようとすると以下の様な例外が発生しました。

> InvalidOperationException: 'EditItem' は、このビューに対して許可されていません。

当然のことながら、コレクションの要素となるクラスには IEditableObject を実装していました。

例外のスタックトレースは以下のとおり。

```
   場所 System.Windows.Controls.ItemCollection.System.ComponentModel.IEditableCollectionView.EditItem(Object item)
   場所 System.Windows.Controls.DataGrid.EditRowItem(Object rowItem)
   場所 System.Windows.Controls.DataGrid.OnExecutedBeginEdit(ExecutedRoutedEventArgs e)
   場所 System.Windows.Controls.DataGrid.OnExecutedBeginEdit(Object sender, ExecutedRoutedEventArgs e)
   場所 System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   ～ 略 ～
```

ILSpy を使って原因を探っていくと、

```c#:ItemCollection.cs
namespace System.Windows.Controls
{
    public sealed class ItemCollection
        : CollectionView, IList, ICollection, IEnumerable, IEditableCollectionViewAddNewItem,
            IEditableCollectionView, ICollectionViewLiveShaping, IItemProperties, IWeakEventListener
    {
        
        // ～ 略 ～
        
        private CollectionView _collectionView;
        
        void IEditableCollectionView.EditItem(object item)
        {
            IEditableCollectionView editableCollectionView = this._collectionView as IEditableCollectionView;
            if (editableCollectionView != null)
            {
                editableCollectionView.EditItem(item);
                return;
            }
            throw new InvalidOperationException(SR.Get("MemberNotAllowedForView", new object[]
            {
                "EditItem"
            }));
        }
    }
}
```
となっており、_collectionView が IEditableCollectionView を実装していないと発生するようです。

以下のようにメソッドを辿って行き、運命の分かれ道を発見しました。

```
ItemCollection.SetCollectionView()
  ItemCollection.SetItemsSource()
    CollectionViewSource.GetDefaultCollectionView()
      CollectionViewSource.GetDefaultCollectionView()
        DataBindEngine.GetViewRecord()
          ViewManager.GetViewRecord()
```

```c#:ViewManager.cs
namespace MS.Internal.Data
{
    internal class ViewManager : HybridDictionary
    {
        internal ViewRecord GetViewRecord(object collection, CollectionViewSource cvs, Type collectionViewType, bool createView, Func<object, object> GetSourceItem)
        {
            
            // ～ 略 ～
            
                  IList list2 = (list != null) ? list : (collection as IList);
                  if (list2 != null)
                  {
                      IBindingList bindingList = list2 as IBindingList;
                      if (bindingList != null)
                      {
                          collectionView = new BindingListCollectionView(bindingList);
                      }
                      else
                      {
                          collectionView = new ListCollectionView(list2);
                      }
                  }
                  else
                  {
                      IEnumerable enumerable = collection as IEnumerable;
                      if (enumerable != null)
                      {
                          collectionView = new EnumerableCollectionView(enumerable);
                      }
                  }
            
            // ～ 略 ～
            
        }
    }
}
```
IList を実装している場合は BindingListCollectionView, ListCollectionView と言う
共に IEditableCollectionView を実装したオブジェクトを返し、

IList を実装していない場合は EnumerableCollectionView と言う
IEditableCollectionView を実装しないオブジェクトを返すようです。


```c#:BindingListCollectionView.cs
namespace System.Windows.Data
{
    public sealed class BindingListCollectionView
        : CollectionView, IComparer, IEditableCollectionView, ICollectionViewLiveShaping, IItemProperties
    {
    }
}
```

```c#:ListCollectionView.cs
namespace System.Windows.Data
{
    public class ListCollectionView
        : CollectionView, IComparer, IEditableCollectionViewAddNewItem,
            IEditableCollectionView, ICollectionViewLiveShaping, IItemProperties
    {
    }
}
```

```c#:EnumerableCollectionView.cs
namespace MS.Internal.Data
{
    internal class EnumerableCollectionView : CollectionView, IItemProperties
    {
    }
}
```

DataGrid を使うときは気をつけましょう。