2009-05-08 11 views
5

¿Cómo determina ListCollectionView.AddNew el tipo de objeto que crea y cómo podría afectarlo uno?Tipo de objeto creado por ListCollectionView.AddNew

que tienen una jerarquía de algunos tipos (Base, DerivedA y DerivedB), y actualmente mi WPF Toolkit DataGrid crea DerivedA objetos (por qué, no sé - probablemente debido a que casi todos los datos de la cuadrícula es de ese tipo), pero me gustaría crear objetos DerivedB en su lugar.

actualización: He intentado derivar una nueva clase de ListCollectionView e implementación de un nuevo método AddNew para ello, y ahora estoy casi allí: el problema único que queda es que después de la adición de un nuevo elemento, un nuevo nuevo el marcador de posición del elemento no se agrega, por lo que solo puedo agregar un elemento. Mi enfoque actual se ve algo como esto:

public class CustomView : ListCollectionView, IEditableCollectionView 
{ 
    public CustomView(System.Collections.IList list) 
     : base(list) 
    { 
    } 

    object IEditableCollectionView.AddNew() 
    { 
     DerivedB obj = new DerivedB(); 
     InternalList.Add(obj); 
     return obj; 
    } 
} 

Respuesta

4

preguntas rancios merecen respuestas frescas :)

derivar una clase a partir de ListCollectionView es el camino que tomé para controlar los objetos que se añaden por AddNew también, pero después de navegar a través de la fuente de ListCollectionView a averiguar lo que hace internamente, encontré que la forma más segura de redefinir AddNew (técnicamente no es una anulación) es usar ListCollectionView.AddNewItem después de crear mi nuevo objeto, para que su código se vea así:

public class CustomView : ListCollectionView, IEditableCollectionView 
{ 
    public CustomView(System.Collections.IList list) 
     : base(list) 
    { 
    } 

    object IEditableCollectionView.AddNew() 
    { 
     DerivedB obj = new DerivedB(); 
     return base.AddNewItem(obj); 
    } 
} 

Esto funciona bien porque, además de tener implementaciones casi idénticas de otro modo, ListCollectionView.AddNew() y ListCollectionView.AddNewItem(object item) tanto llamada AddNewCommon(object newItem):

public object AddNew() 
     { 
      VerifyRefreshNotDeferred(); 

      if (IsEditingItem) 
      { 
       CommitEdit(); // implicitly close a previous EditItem 
      } 

      CommitNew();  // implicitly close a previous AddNew 

      if (!CanAddNew) 
       throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNew")); 

      return AddNewCommon(_itemConstructor.Invoke(null)); 
     } 

     public object AddNewItem(object newItem) 
     { 
      VerifyRefreshNotDeferred(); 

      if (IsEditingItem) 
      { 
       CommitEdit(); // implicitly close a previous EditItem 
      } 

      CommitNew();  // implicitly close a previous AddNew 

      if (!CanAddNewItem) 
       throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNewItem")); 

      return AddNewCommon(newItem); 
     } 

AddNewCommon es donde sucede toda la magia real; arranques, llamando BeginInit y BeginEdit en el nuevo elemento si es compatible, y, finalmente, a través de devoluciones de llamada en la cuadrícula de datos, estableciendo los enlaces celulares:

object AddNewCommon(object newItem) 
     { 
      _newItemIndex = -2; // this is a signal that the next Add event comes from AddNew 
      int index = SourceList.Add(newItem); 

      // if the source doesn't raise collection change events, fake one 
      if (!(SourceList is INotifyCollectionChanged)) 
      { 
       // the index returned by IList.Add isn't always reliable 
       if (!Object.Equals(newItem, SourceList[index])) 
       { 
        index = SourceList.IndexOf(newItem); 
       } 

       BeginAddNew(newItem, index); 
      } 

      Debug.Assert(_newItemIndex != -2 && Object.Equals(newItem, _newItem), "AddNew did not raise expected events"); 

      MoveCurrentTo(newItem); 

      ISupportInitialize isi = newItem as ISupportInitialize; 
      if (isi != null) 
      { 
       isi.BeginInit(); 
      } 

      IEditableObject ieo = newItem as IEditableObject; 
      if (ieo != null) 
      { 
       ieo.BeginEdit(); 
      } 

      return newItem; 
     } 

Aquí he incluido el código fuente para mi TypedListCollectionView, que utilizo para controlar el comportamiento AddNew cuando no sé qué tipo será necesaria en tiempo de diseño:

public class TypedListCollectionView : ListCollectionView, IEditableCollectionView 
    { 
     Type AddNewType { get; set; } 

     public TypedListCollectionView(System.Collections.IList source, Type addNewType) 
      : base(source) 
     { 
      AddNewType = addNewType; 
     } 

     object IEditableCollectionView.AddNew() 
     { 
      object newItem = Activator.CreateInstance(AddNewType); 
      return base.AddNewItem(newItem); 
     } 
    } 

me gusta este enfoque, ya que proporciona la máxima flexibilidad para los casos en que puede necesitar ser ajustados en tiempo de ejecución de AddNew 's tipo de uno a otro. También permite que AddNew funcione para agregar el primer elemento de la colección, lo que es útil cuando el origen de la lista está inicialmente vacío, pero se puede determinar su tipo subyacente.

This link se describe una forma alternativa de forzar el tipo utilizado por AddNew(). Utiliza la reflexión para establecer la propiedad privada _itemConstructor utilizada por AddNew en un constructor sin parámetros de un tipo especificado.Esto sería particularmente útil cuando su ListCollectionView proviene de un componente que está fuera de su influencia, o necesita agregar funcionalidad al código existente y está preocupado por romper las cosas (lo que nunca sucede porque soy un codicioso codificador que con insensibilidad) Cansos con colecciones).

+0

Cambié la arquitectura de mi aplicación, así que esto ya no es un problema para mí, pero su respuesta parece plausible basándome en solo mirarla. –

+0

Por alguna razón, no parece haber aceptado esta respuesta el año pasado. –

1

TomiJ,

ver si ayuda, pero no es la respuesta ok?

http://www.cnblogs.com/winkingzhang/archive/2008/05/22/1204581.html

+1

El artículo (el original se encuentra en ) fue de algunos ayuda, ya que me hizo mirar 'ListCollectionView'. –

+0

Veo, logré obtener la respuesta correcta, no se olvide de actualizar aquí. Es una pregunta muy interesante: D –

+0

Todavía no he llegado, ya que solo puedo agregar _un_ nuevo elemento, pero al menos se llama al método AddNew correcto. Tendré que descubrir qué más necesito implementar para obtener la funcionalidad adecuada. –

1

En .NET 4, ahora hay una nueva interfaz IEditableCollectionViewAddNewItem, implementada por ListCollectionView, que posee un nuevo método AddNewItem(object). Puede usarlo en lugar de AddNew() para controlar el elemento recién agregado.

+0

De hecho lo hay, y esta respuesta es igual de aceptable que la de Erikest que he aceptado (en virtud de que esa respuesta es más antigua y también menciona 'ListCollectionView.AddNewItem (object)'). –

Cuestiones relacionadas