Aggiungere item CascadingDropDown

martedì 11 maggio 2010 - 22.01

Pinky Profilo | Junior Member

All'interno di una pagina molto estesa e complicata ho varie DropDownList con collegate delle CascadingDropDown dell'AjaxControlToolKit (una versione non aggiornatissima).
Tale CDD (CascadingDropDown) è collegata alla DDL (DropDownList) e quindi si occupa di valorizzarla.

Il mio problema è il dover aggiungere degli item NON presenti ma che sono richiesti in un caso particolare.

Se non vi fosse stata la CDD avrei sfruttato l'evento OnDataBound per verificare l'esistenza del valore voluto ed eventualmente aggiungerlo come nuovo ListItem alla lista. Questa in sostanza è la logica da applicare. Ora questo non è possibile perchè non avendo un classico binding l'evento citato ed altri non vengono scatenati.
Invece la CDD espone solamante l'evento OnDataBinding che però non viene scatenato (googlando mi è sembrato di capire che vecchie versioni dell'AjaxControlToolKit potrebbero avere tale problema).

Allora ho preso una strada diversa. Mi sono messo nell'evento OnPreRender della pagina e ho aggiunto il ListItem a mano, ma non viene renderizzato.

Come posso aggiungere degli item (oltre a quelli "naturalmente" caricati dalla richiesta al web service del CascadingDropDown) alla DropDownList?

Grazie
Alessandro

purtroppo mi è scappato il titolo provvisorio, avrei voluto mettere "CascadingDropDown impedisce aggiunta items a DropDownList", non è possibile editarlo?

Gluck74 Profilo | Guru

Ciao,
secondo me ci possono essere diversi modi per inserire il valore da te voluto manualmente, all'interno della sista dei valori da visualizzare nella comboBox.
Dipende anche da come carichi i valori del Cascading.
Io ad esempio uso un WebService richiamato dal cascadingDropDown, quindi agirei in quel punto.
Ad esempio questo il mio codice:

[WebMethod] [System.Web.Script.Services.ScriptMethod()] public CascadingDropDownNameValue[] getProdottiDDL(string knownCategoryValues, string category) { List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>(); //values.Add(new CascadingDropDownNameValue("", "")); DS_Amministrazione ds = new DS_Amministrazione(); foreach (DataRow dr in ds.getProdottiDDL().Rows) { values.Add(new CascadingDropDownNameValue(dr[1].ToString(), dr[0].ToString())); } return values.ToArray(); }

quindi prima di fare il return, potresti aggiungere appunto il valore che ti manca:
values.Add(new cascadingDropDownNameValue(string name, string value);
oppure puoi usare il metodo "Insert" per specificare anche la posizione:
values.Insert(int index, new cascadingDropDownNameValue(string name, string value);

Ciao e buon lavoro

Pinky Profilo | Junior Member

Innanzi tutto grazie dell'interessamento.
Per prima cosa si; il CascadingDropDown è caricato con web service.
Però in tale metodo non posso intervenire per aggiungere l'item in quanto questo è determinato in un certo evento della pagina, indipendentemente dal metodo.
Illustro la situazione per capire quale potrebbe essere una soluzione valida.

Ho una pagina che ad esempio gestisce un oggetto Contratto. Uno dei campi di tale contratto è la provincia. Quindi verrà mostrata una casella di scelta (DropDownList) che mostra le province. Essendo a questa poi legato il comune ed il CAP e "gerarchicamente sopra" la nazione ecco il perchè hanno usato dei CascadingDropDown.
Adesso ammettiamo che io abbia 3 province attualmente assegnate all'utente (competenza territoriale).
Se vado in editing di un contratto stipulato in precedenza dove vi era una provincia (Id+ Descrizione) che invece ora è fuori dalle mie competenze attuali ho il duplice problema che non riesco a visualizzarne (e selezionarne) il relativo item sulla combo ed un eventuale salvataggio mi modificherebbe il Contratto (l'Id della provincia).

Quindi la sequenza corretta sarebbe:
1) Load delle Province e caricamento della DropDownList tramite l'apposito metodo nel web service che ritorna le province di mia competenza (più item nullo).
2) Lettura dell'oggetto Contratto con tutte le sua proprietà.
2) Set della proprietà SelectedValue sulla CascadingDropDown che si ripercuote sulla DropDownList.
3a) Se il valore esiste viene correttamente selezionato (ed il salvataggio è coerente).
3b) Se il valore non è presente rimane selezionato l'item nullo (Id = 0, "Selezionare...") ed il salvataggio va in errore.

La mia idea era quindi intervenire dopo il caricamento e tramite un FindByValue() chiamato sulla DropDownList (od altro metodo) verificare la presenza della provincia X, e se necessario aggiungere il ListItem creato "manualmente".

Da una prova fatta ho capito che modificare gli item della DropDownList non ha alcun effetto.
Non ho però trovato il modo per modificare la collezione di item della CascadingDropDown... credo infatti che non sia stato contemplato dagli sviluppatori dell'extender.
Chiaramente l'item aggiunto deve eseere valido per il postback e scatenare l'evento come fosse derivato dalla chiamata originale al web service.
Non sarebbe per nulla elegante ma potrebbe essere una soluzione il passaggio di un parametro aggiuntivo (Id provincia esistente) al metodo del web service...

Per ora vengono caricate tutte le province ed al salvataggio si effettua una verifica (se sono in creazione non si accettano province non valide)
ma questa è una toppa, non una soluzione...

Grazie
Alessandro

Gluck74 Profilo | Guru

Ciao Pinky,

mi sembra strato che la soluzione che ti ho dato non funzioni.
All'interno del metodo chiamato per popolare il CascadingDDL, in effetti crei tu tutti gli item da un recordset, e puoi anche aggiungere items arbitrari semplicemente aggiungendo una riga di questo genere:

values.Insert(3, new cascadingDropDownNameValue("prova", "99");
(aggiungo come 4° items, il valore 99 con testo prova)


è vero in effetti che dal metodo non sai i valori della provincia da aggiungere, ma potresti passare ad un servizio la Session, e quindi risolveresti il problema.
[WebMethod(EnableSession = true)]
però devi prima caricare il contratto, poi la combo.


Altra soluzione è agire nel PreRender della DDL.
A questo punto tutti gli item derivanti dal WebSerice sono già presenti, quindi inserisci se necessario la provincia mancante.

Pinky Profilo | Junior Member

La soluzione da te indicata funziona, ma non riesco ad apllicarla nel mio contesto.

Partiamo dal "PreRender" che mi pare la soluzione più "corretta" perchè rimarrebbe nella pagina e non semi-nascosta nel webservice.
Se per "agire nel PreRender della DDL" intendi fare qualcosa del tipo (pseudo-codice):
if(ddl.FindByValue(contratto.provincia.Id) == null) {
ddl.Items.Add( new ListItem(contratto.provincia.Id.ToString(), provincia.Descrizione) );
cdd.SelectedValue = ddl.SelectedValue = contratto.provincia.Id.ToString();
}
ho già provato e non funziona (anche senza l'IF...), sia nel PreRender della Page (prima e dopo chiamare base.PreRender) sia nell'evento cboProvincia_PreRender.
In effetti ne ho dedotto che la collezione degli Item della DDL sia TOTALMENTE IGNORATA a causa dell'extender (in effetti togliendo questo il mio item correttamente appare).

Torniamo quindi al metodo più naturale dell'item aggiunto dal metodo del web service.
Non riesco ad applicarlo, perchè non conosco l'item da aggiungere manualmente, ne so come dirlo al metodo che restituisce i valori per la combo.
Il Session è disabilitato da web.config ( <httpModules> <remove name="Session"/> </httpModules>, per mia insindacabile scelta ),
quindi ci vorrebbe un altro modo per passare l'Id della provincia presente nel contratto.
Potrei provare ad usare il ContextKey (che in effetti è già utilizzato per altri scopi), ad esempio concatenandoci ":[id_provinciacontratto o -1]" e poi facendo uno split sull' ":" e ricavato un ID positivo sfruttarlo per caricare la provincia mancante.
Ma anche se funzionasse è una "porcata"...

Rimango dell'opinione che "manca qualcosa" all'extender...

Ho fatto una pagina di test semplice semplice ed ho scoperto (con orrore!) che è necessario inserire EnableEventValidation="false" come se avessi buttato dentro gli item con del javascript inserito da me,
ma perchè con il CascadingDropDown non se ne occupa il Framework di registrare gli item come validi?!

Grazie
Alessandro

Pinky Profilo | Junior Member

Niente da fare... per risolvere ho dovuto aggiungere un ulteriore parametro al ContextKey che ne conteneva già un paio.

Dato che i due parametri precedenti (id utente e lingua) sono presenti sempre, vengono messi nel ContextKey nell'Init della pagina.

Invece il mio parametro facoltativo (Id provincia del contratto) è inserrito in un punto differente, ovvero nella funzione che si occupa di leggere il contratto e caricare tutti i controlli della pagina. Quindi ora il codice per gestire queste combo in cascata è pericolosamente "sparso" in più punti, per questo preferivo poter editare direttamente la collezione di item della combo o dell'extender.

Dato che mi pare non ci sia alternativa ed ora sembra funzionare tutto lascio le cose come stanno.
Per gestire caselle di scelta in cascata ho sempre e solo usato DropDownList inserite in UpdatePanel e continuerò a fare così... anche perè il codice per gestirle con la chiamata al web service mi pare un pò troppo farraginoso.

Grazie
Alessandro

Gluck74 Profilo | Guru

ciao Pinky,

non ricordo benissimo il funzionamento delle CascadingDDl lato Client, ma potrebbe esserci una soluzione javascript. Se la trovo ti dico.

Il fatto di aver passato un parametro al context, non è poi così male. Non è molto leggibile in effetti, ma anche io ho utilizzato soluzioni del genere.
Il codice non diventa poi così più "sparpagliato" dei quello che lo è già utilizzando i webservice e i controlli ajax.

Un'altra soluzione, che potrebbe tagliare la testa al toro, è di agire lato SQL.
La funzione che carica da webservice i dati, nel momento che chiama la query per caricare le provincie, passa la provincia "default" che sarebbe quella del contratto, e lo fai fare alla query.

ciao ciao
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5