2009-05-08 12 views
5

In che modo ListCollectionView.AddNew determina il tipo di oggetto che crea e come può influire su di esso?Tipo di oggetto creato da ListCollectionView.AddNew

Ho una gerarchia di qualche tipo (Base, DerivedA, e DerivedB), e attualmente il mio WPF Toolkit DataGrid crea DerivedA oggetti (perché, non lo so - probabilmente perché quasi tutti i dati nella griglia è di quel tipo), ma mi piacerebbe creare invece gli oggetti DerivedB.

Aggiornamento: Ho provato derivare una nuova classe da ListCollectionView e l'attuazione di un nuovo metodo AddNew per esso, e ora sono quasi arrivato: l'unico problema e 'che dopo l'aggiunta di un nuovo elemento, una nuova nuova il segnaposto dell'articolo non viene aggiunto, quindi posso aggiungere solo un elemento. Il mio attuale approccio sembra un po 'come questo:

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; 
    } 
} 

risposta

4

domande Stale meritano nuove risposte :)

derivazione di una classe da ListCollectionView è il percorso ho preso per controllare gli oggetti che viene aggiunto da AddNew pure, ma dopo la navigazione attraverso la fonte di ListCollectionView a scoprire che cosa fa internamente, ho trovato che il modo più sicuro per ridefinire AddNew (non è tecnicamente un override) è usare ListCollectionView.AddNewItem dopo aver creato il mio nuovo oggetto, quindi il tuo codice sarebbe il seguente:

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

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

Questo funziona bene perché, oltre ad avere implementazioni quasi identiche altrimenti, ListCollectionView.AddNew() e ListCollectionView.AddNewItem(object item) sia chiamata 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 è dove tutta la vera magia accade; accensioni, chiamando BeginInit e BeginEdit sul nuovo elemento se supportato, e, infine, attraverso i callback sulla DataGrid, che stabilisce le associazioni di cella:

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; 
     } 

Qui ho incluso il codice sorgente alla mia TypedListCollectionView, che io uso per controllare il comportamento AddNew quando non so che tipo saranno necessari in fase di progettazione:

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); 
     } 
    } 

mi piace questo approccio in quanto offre la massima flessibilità per i casi in cui può avere bisogno di essere regolata in fase di esecuzione da AddNew s' tipo uno all'altro. Permette anche a AddNew di lavorare per aggiungere il primo elemento della collezione, il che è utile quando l'origine dell'elenco è inizialmente vuota, ma il suo tipo sottostante può essere determinato.

This link discute un modo alternativo per forzare il tipo utilizzato da AddNew(). Usa la riflessione per impostare la proprietà privata _itemConstructor utilizzata da AddNew su un costruttore senza parametri di un tipo specificato.Questo sarebbe particolarmente utile quando il tuo ListCollectionView proviene da un componente che è al di fuori della tua influenza, o hai bisogno di aggiungere funzionalità al codice esistente e sei preoccupato di rompere le cose (cosa che non sono mai perché sono un programmatore spregiudicato che insensibilmente cariati con collezioni).

+0

Ho cambiato l'architettura nella mia applicazione, quindi questo non è più un problema per me, ma la tua risposta sembra plausibile basandoti solo a guardarla. –

+0

Per qualche motivo, non ho accettato questa risposta l'anno scorso. –

1

TomiJ,

vedere se aiuta, ma non è la risposta ok?

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

+1

L'articolo (quello originale è ) era di alcuni aiuto, dato che mi ha spinto a guardare 'ListCollectionView'. –

+0

Vedo, sono riuscito a ottenere la risposta giusta, non dimenticarti di aggiornare qui. È una domanda molto interessante: D –

+0

Non ci sono ancora abbastanza, dato che posso aggiungere solo _ un_ nuovo elemento, ma almeno viene chiamato il metodo AddNew corretto. Dovrò capire cos'altro ho bisogno di implementare per ottenere la corretta funzionalità. –

1

In .NET 4, ora è disponibile una nuova interfaccia IEditableCollectionViewAddNewItem, implementata da ListCollectionView, che possiede un nuovo metodo AddNewItem(object). Puoi usarlo invece di AddNew() per controllare l'elemento appena aggiunto.

+0

Infatti c'è, e questa risposta è ugualmente ok come quella di Erikest che ho accettato (in virtù della risposta che è più vecchia e che menziona anche 'ListCollectionView.AddNewItem (oggetto)'). –

Problemi correlati