2010-02-08 5 views
7

All'interno di un controllo ripetitore, esiste un modo per deselezionare determinati elementi prima che la pagina venga visualizzata?Controllo ripetitore - Annulla binding per articolo specifico

Attualmente abbiamo una raccolta di elementi collegati a un ripetitore e se l'elemento non fa parte della lingua corrente, nascondiamo l'elemento.

Sto volendo essere in grado di fare un conteggio sul ripetitore e ottenere un numero valido indietro. Un conteggio che non include anche gli oggetti nascosti.

È possibile annullare l'associazione di elementi specifici nell'evento ItemDataBound?

Aggiornamento

Per ogni elemento della collezione stiamo vincolante, controlliamo il database durante la ItemDataBound per ulteriori informazioni sulla voce, come la lingua, ecc Questo è attualmente ci impedisce di filtrare il limite dati prima di legarli

risposta

2

Sono d'accordo con le altre risposte: la soluzione migliore (sia per le prestazioni che per la chiarezza del codice) è ridisegnare la pagina in modo da poter filtrare le voci non valide prima prima di .

La maggior parte delle origini dati non ci consente di rimuovere i loro articoli mentre ASP.NET li sta iterando. Ad esempio, se si associa a un semplice generico List<T> e si rimuove un elemento mentre lo si itera, l'elenco genererà un valore InvalidOperationException.

In altri casi, ASP.NET esegue effettivamente una copia dell'origine dati. Se si esegue il binding a un DataTable, ASP.NET utilizza una copia del contenuto (il DataView predefinito) anziché iterare le stesse righe di origine: è possibile rimuovere gli elementi dall'origine dati sottostante durante l'iterazione, ma non influisce sull'operazione di associazione dei dati .

Se filtrare gli articoli in anticipo non è un'opzione, la soluzione corrente va bene: basta nascondere gli articoli! Se avete bisogno di ottenere il conteggio corretto per di più, tenere traccia del numero di elementi non validi nel vostro gestore ItemDataBound ed esporre come una proprietà a livello di pagina:

if (IsInvalid(args.Item.DataItem)) { 
    this.invalidItemCount++; 
    // code to hide the current item 
} 
+0

Mi piacerebbe riprogettare il modo in cui funzionano le pagine ma stiamo usando EPiServer come CMS e per quanto ho trovato, l'attuale il modo migliore è quello che sono riuscito a trovare. Attualmente sto seguendo la tua ultima segnalazione per esporre una proprietà Count e incrostarla per gli articoli validi. Potrebbe essere necessario attenersi a quello. Grazie per la risposta :) –

3

Una soluzione più appropriata potrebbe essere quella di filtrare la raccolta associata se non vi è alcuna necessità specifica in quegli elementi nascosti. Qualcosa di simile

items.Where(i => i.IsInLanguage(currentLanguage)); 

Aggiornamento:

Quanto a me userei questo approccio:

var items = db. 
     Where(i => i.IsInLanguage(currentLanguage)). 
     Where(i => i.SomeField == anotherFilterParameter); 

repeater.DataSource = items; 
repeater.DataBind(); 

Quindi tutto il filtraggio viene applicato in anticipo

questo ridurrà il numero di round- viaggi al database, che gioca per prestazioni migliori

+0

Aggiornerò il mio OQ ma fondamentalmente, non sappiamo quali elementi impostare come visibili ecc. Fino all'evento ItemDataBound. Ogni articolo ha un ID e andiamo al DB per ulteriori dettagli a quel punto. –

+0

Cosa succede su ItemDataBound che rende possibile il filtraggio? La tua lingua attuale sta diventando disponibile solo in quel momento? –

+0

sì. Fondamentalmente abbiamo qualcosa chiamato una raccolta di ID di "pagina" e dato che ogni oggetto è legato, andiamo al database, scopriamo se è parte della lingua corrente e se no, nascondi l'oggetto. –

2

Perché non filt er l'origine dati prima del binding. Quindi supponendo che stai usando alcuni oggetti personalizzati:

myRepeater.DataSource=repository.getItems().Where(item=>item.Language==CurrentLanguage); 

Se non ne hai bisogno, non vincolarli in primo luogo.

Aggiornamento

Se è a tutto il possibile si dovrebbe probally tirare queste informazioni dal anticipo DB. Queste liste sono grandi? Se così colpendo il db una volta per ogni elemento nell'elenco verrà visualizzato come un problema di prestazioni.

2

La risposta è molto semplice basta impostare la Visible proprietà a false sull'elemento e non sarà reso. In questo esempio sto rimozione di elementi da un elenco di prodotti che sono disponibili solo per i nuovi clienti, se l'utente corrente ha una cronologia degli acquisti:

void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e) 
     { 
      if (!userHasPurchaseHistory) { return; } 
      // filter out products only allowed for new members 
      if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) 
      { 
       System.Data.Common.DbDataRecord rec = (System.Data.Common.DbDataRecord)e.Item.DataItem; 
       if (rec != null) 
       { 
        bool newMemberOnly = Convert.ToBoolean(rec["NewMemberOnly"]); 
        if (newMemberOnly) { e.Item.Visible = false; } 
       } 
      } 

     } 

Si noti che quanto sopra è databound a un IDataReader, potrebbe essere necessario lanciare e.Item.DataItem in un oggetto diverso a seconda di ciò a cui si sta vincolando.

Si noti inoltre che non eseguirò mai un'altra ricerca del database durante l'associazione, non si dovrebbe mai accedere al database in un ciclo ma fintanto che i dati a cui si sta vincolando hanno qualcosa che è possibile controllare per decidere se si desidera mostrare non c'è niente di sbagliato con il filtro in ItemDataBound. Potrebbe essere problematico se si sta facendo qualsiasi tipo di paging poiché ciò renderebbe il rendering di dimensioni di pagina non coerenti.