2008-12-12 6 views
8

Un esempio è descritto here. Apparentemente l'autore ha dimenticato di includere il codice per il download.Come creare una StateManagedCollection generica?

Un altro esempio viene mostrato here. Tuttavia, questo non funziona (come descritto nei commenti).

Come si fa a farlo correttamente?

+0

Ecco un [collegamento aggiornato al 2 ° esempio] (http://blog.spontaneouspublicity.com/child-collections-in-asp-net-custom-controls) –

+0

Grazie per l'aggiornamento. – Larsenal

risposta

3

DanHerbert ci è riuscito. Maledizione, ho passato ore anche su questo! Nel tentativo di rispondere a questa domanda, mi è venuto in mente uno StateManagedCollection generico semplificato che eredita dallo StateManagedCollection incorporato nel framework, basato sulla versione here. Forse lo troverai utile Il codice sorgente completo del mio progetto di esempio è disponibile here.

using System; 
using System.Collections; 
using System.Collections.Specialized; 
using System.Security.Permissions; 
using System.Web; 
using System.Collections.Generic; 
using System.Web.UI; 

namespace Web 
{ 
    public abstract class StateManagedCollection<T> : StateManagedCollection, IList<T>, ICollection<T>, IEnumerable<T> 
     where T : class, IStateManagedItem, new() 
    { 

     protected override object CreateKnownType(int index) 
     { 
      return Activator.CreateInstance<T>(); 
     } 

     protected override Type[] GetKnownTypes() 
     { 
      return new Type[] { typeof(T) }; 
     } 

     protected override void SetDirtyObject(object o) 
     { 
      ((IStateManagedItem)o).SetDirty(); 
     } 

     #region IList<T> Members 

     public int IndexOf(T item) 
     { 
      return ((IList)this).IndexOf(item); 
     } 

     public void Insert(int index, T item) 
     { 
      ((IList)this).Insert(index, item); 
      if (((IStateManager)this).IsTrackingViewState) 
      { 
       this.SetDirty(); 
      } 
     } 

     public void RemoveAt(int index) 
     { 
      ((IList)this).RemoveAt(index); 
      if (((IStateManager)this).IsTrackingViewState) 
      { 
       this.SetDirty(); 
      } 
     } 

     public T this[int index] 
     { 
      get { return (T)this[index]; } 
      set { this[index] = value; } 
     } 

     #endregion 

     #region ICollection<T> Members 

     public void Add(T item) 
     { 
      ((IList)this).Add(item); 
      this.SetDirty(); 
     } 

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

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

     public bool IsReadOnly 
     { 
      get { return false; } 
     } 

     public bool Remove(T item) 
     { 
      if (((IList)this).Contains(item)) 
      { 
       ((IList)this).Remove(item); 
       return true; 
      } 
      return false; 
     } 

     #endregion 


     #region IEnumerable<T> Members 

     IEnumerator<T> IEnumerable<T>.GetEnumerator() 
     { 
      throw new NotImplementedException(); 
     } 

     #endregion 

     #region IEnumerable Members 

     IEnumerator IEnumerable.GetEnumerator() 
     { 
      return ((IList)this).GetEnumerator(); 

     } 

     #endregion 
    } 
} 
+0

Scelta difficile per il premio di taglie, ma il codice sorgente completo è molto utile. Grazie. – Larsenal

+0

Non stai implementando IEnumerable .GetEnumerator(). Se si utilizza .NET 3.5, è possibile sostituire tale lancio con il seguente: ((IEnumerable ).). Da () .GetEnumerator(); –

+0

Potrebbe dirmi dove posso scaricare il codice sorgente di esempio? Coz 'il link che mi hai fornito mi fornisce un messaggio di errore. –

4

Il second example you found funziona quasi, manca solo un po '. Tutto ciò che era necessario era 2 metodi nel controllo principale.

Aggiungere questo codice al file AppointmentControl.cs e funzionerà.

protected override object SaveViewState() 
{ 
    if (appointments != null) 
     return appointments.SaveViewState(); 
    return null; 
} 

protected override void LoadViewState(object savedState) 
{ 
    appointments = new AppointmentCollection(); 
    appointments.LoadViewState(savedState); 
} 

Il codice nel sito di esempio era abbastanza decente. Ha implementato tutte le interfacce che dovrebbe avere e ha fatto un buon lavoro. Dove si separava era che, nonostante avesse tutto il codice di cui aveva bisogno nei bit astratti, non importava perché le interfacce non erano referenziate nei posti che dovevano essere.

Le classi di raccolta utilizzate non avevano nulla di "speciale" su di esse, a parte l'implementazione di alcune interfacce. Il framework non chiamerà automaticamente questi metodi. Il framework invierà tuttavia richiamare i metodi sovrascritti che ho scritto sopra, che è necessario implementare affinché il controllo possa salvare gli elementi nella raccolta. Finché li chiami, tutto funzionerà.

0

Ho usato il codice sopra la soluzione fornita è ok, ma mi è stato sempre un'eccezione - "StackOverflow" cool :) il problema è riproducibile con l'aggiunta di alcuni elementi figlio nella pagina aspx e passare alla visualizzazione a vista di progettazione di Visual Studio (Visual Studio appena riavviato e nessuno sa cosa sta succedendo ....).

IEnumerator IEnumerable.GetEnumerator() 
    { 
     return ((IList)this).GetEnumerator(); 

    } 

Quindi, credo che ho capito solo cambiare l'applicazione del metodo di cui sopra in questo modo:

IEnumerator IEnumerable.GetEnumerator() 
    { 
     // return ((IList)this).GetEnumerator(); 
     return this.GetEnumerator(); 

    } 

Spero che questo vi aiuterà a qualcun altro come me :) giusto per non perdere poche ore a farlo funzionare con il designer di VS