WPF ‘EditItem’ no está permitido para esta vista

Sé que hay muchas preguntas ( 1 , 2 , 3 , 4 , 5 , etc.) sobre ese error, pero no puedo encontrar una que explique la causa de este error y que sea adecuada para mi caso. Déjame saber si me pierdo uno!

En primer lugar, estoy ItemsSource a mi DataGrid ItemsSource con una clase personalizada (no ObservableCollection o cualquier otra colección observable incorporada .NET). Antes de mostrarle su código, permítame explicarle cómo lo pensé (mis suposiciones pueden estar equivocadas).

En mi opinión, para ser vinculable, una colección debe implementar al menos IEnumerable e INotifyCollectionChanged . IEnumerable para que la vista obtenga los elementos a mostrar (gracias al método GetEnumerator ) e INotifyCollectionChanged para que la vista conozca los cambios en la colección.

Así que termino con esta clase:

 public class ObservableDictionary : IDictionary, IEnumerable, INotifyCollectionChanged { #region fields private IDictionary _innerDictionary; #endregion #region properties public int Count { get { return _innerDictionary.Count; } } public ICollection Keys { get { return _innerDictionary.Keys; } } public ICollection Values { get { return _innerDictionary.Values; } } public bool IsReadOnly { get { return false; } } #endregion #region indexors public TValue this[TKey key] { get { return _innerDictionary[key]; } set { this.InternalAdd(new KeyValuePair(key, value)); } } #endregion #region events public event NotifyCollectionChangedEventHandler CollectionChanged; #endregion #region constructors public ObservableDictionary() { _innerDictionary = new Dictionary(); } public ObservableDictionary(int capacity) { _innerDictionary = new Dictionary(capacity); } public ObservableDictionary(IEqualityComparer comparer) { _innerDictionary = new Dictionary(comparer); } public ObservableDictionary(IDictionary dictionary) { _innerDictionary = new Dictionary(dictionary); } public ObservableDictionary(int capacity, IEqualityComparer comparer) { _innerDictionary = new Dictionary(capacity, comparer); } public ObservableDictionary(IDictionary dictionary, IEqualityComparer comparer) { _innerDictionary = new Dictionary(dictionary, comparer); } #endregion #region public methods public bool ContainsKey(TKey key) { return _innerDictionary.ContainsKey(key); } public bool Contains(KeyValuePair item) { return _innerDictionary.Contains(item); } public void Add(TKey key, TValue value) { this.InternalAdd(new KeyValuePair(key, value)); } public void AddRange(IEnumerable<KeyValuePair> items) { if (!items.Any()) { return; } var added = new List(); var removed = new List(); foreach (var item in items) { TValue value; if (_innerDictionary.TryGetValue(item.Key, out value)) { removed.Add(value); } added.Add(item.Value); _innerDictionary[item.Key] = item.Value; } this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added, null)); if (removed.Count > 0) { this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, removed)); } } public void Add(KeyValuePair item) { this.InternalAdd(item); } public bool TryGetValue(TKey key, out TValue value) { return _innerDictionary.TryGetValue(key, out value); } public bool Remove(TKey key) { return this.InternalRemove(key); } public bool Remove(KeyValuePair item) { return this.InternalRemove(item.Key); } public void Clear() { _innerDictionary.Clear(); this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { _innerDictionary.CopyTo(array, arrayIndex); } public IEnumerator GetEnumerator() { return Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } IEnumerator<KeyValuePair> IEnumerable<KeyValuePair>.GetEnumerator() { return _innerDictionary.GetEnumerator(); } #endregion #region private methods ///  /// Adds the specified value to the internal dictionary and indicates whether the element has actually been added. Fires the CollectionChanged event accordingly. ///  ///  ///  private void InternalAdd(KeyValuePair item) { IList added = new TValue[] { item.Value }; TValue value; if (_innerDictionary.TryGetValue(item.Key, out value)) { this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, new TValue[] { value })); } _innerDictionary[item.Key] = item.Value; this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added, null)); } ///  /// Remove the specified key from the internal dictionary and indicates whether the element has actually been removed. Fires the CollectionChanged event accordingly. ///  ///  ///  private bool InternalRemove(TKey key) { TValue value; if (_innerDictionary.TryGetValue(key, out value)) { _innerDictionary.Remove(key); this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, null, new TValue[] { value })); } return value != null; } #endregion } 

Implementa implícitamente el IEnumerable.GetEnumerator y explícitamente los otros métodos GetEnumerator ( IDictionary e IEnumerable ) para que mi vista muestre solo los valores de mi diccionario, y mapeo los métodos agregar / eliminar en torno a la invocación del evento CollectionChanged .

Mi ViewModel se define así:

 class MyViewModel { public ObservableDictionary Foos { get; private set; } public MyViewModel() { this.Foos = new ObservableDictionary(); } } 

Y lo unen a mi punto de vista así:

        

Luego, cuando bash editar el Valor, aparece el error especificado:

‘EditItem’ no está permitido para esta vista

Cuando coloco algunos puntos de interrupción en mi código, nunca alcanzo el configurador de indexador ObservableDictionary ni el de Foo.Value .

¿Mis pensamientos acerca de cómo la vista obtiene el elemento de las correcciones de la colección enlazada? ¿Por qué recibo este error y / o cómo puedo autorizar mi vista a EditItem ?

Su tipo de colección de origen ( ObservableDictionary ) debe implementar la interfaz IList si desea poder editar los datos en un DataGrid .

Cada vez que se enlaza con alguna propiedad de colección en WPF, siempre se enlaza con una vista generada automáticamente y no con la propia colección de origen.

El tipo de vista que el tiempo de ejecución crea para usted depende del tipo de la colección fuente y su colección fuente debe implementar la interfaz IList no genérica para que funcione la funcionalidad de edición interna del control DataGrid .