ASP.NET ha una nutrita serie di controlli studiati per le più disparate esigenze di visualizzazione dati, ciò nonostante è del tutto assente un campo per la visualizzazione di una DropDownList in un Data Control, come GridView o DetailsView.
Benché il problema sia facilmente risolvibile utilizzando la malleabile TemplateField, alla lunga tale soluzione è scomoda specialmente se costretti a ripetere il medesimo markup in più pagine.
Per evitare di cadere in errori causati da copia/incolla, la soluzione migliore consiste nel realizzare un field come custom contro.
Il primo passo è decidere la classe da derivare, nel nostro caso la scelta più adatta è la classe BoundField perché dispone già di un metodo per formattare i dati, FormatDataValue, ed uno per recuperare dalla fonte dati il campo da visualizzare, GetValue.
I metodi di cui è indispensabile eseguire l'override sono tre: InizializzeDataCell, ExtractValuesFromCell e OnDataBindField.
InizializzeDataCell viene eseguito ogniqualvolta è necessario aggiungere a una cella il controllo o i controlli necessari a visualizzare i dati provenienti dalla fonte dati e non viene richiamato per creare l'header o il footer.
Per realizzare la nostra field custom è necessario aggiungere alla cella una DropDownList, qualora si trovi in modalità di Edit o Insert, e registrare per l'evento DataBound un event handler che punti al metodo OnDataBindField. Infine per recuperare la selezione dell'utente basta sfruttare l'override del metodo ExtractValuesFromCell.
protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState) { // controllo se devo aggiungere la DropDownList if (IsInputMode(rowState)) { // la istanzio DropDownList _dropDownList = new DropDownList(); // e imposto le proprietà necessarie _dropDownList.DataTextField = DataTextField; _dropDownList.DataValueField = DataValueField; _dropDownList.AppendDataBoundItems = true; //aggiungo un elemento neutro _dropDownList.Items.Add(new ListItem(ItemTextEmptyValue, ItemValuetEmptyValue)); // aggiungo il controllo alla cella cell.Controls.Add(_dropDownList); //se sono in DesignMode if (DesignMode) { if (!string.IsNullOrEmpty(DataSourceID)) _dropDownList.Items.Add("DataBound"); } else { //imposto la sorgente dati _dropDownList.DataSourceID = DataSourceID; //per la modalità Insert non ho bisogno di gesire l'evento if ((rowState & DataControlRowState.Insert) != DataControlRowState.Insert) _dropDownList.DataBound += new EventHandler(OnDataBindField); } } else { cell.DataBinding += new EventHandler(OnDataBindField); } }
In seguito eseguiamo l'override del metodo OnDataBindField, eseguito come risposta all'evento DataBound della DropDownList (modalita di Edit e Insert) e per quello di DataBind della cella.
Nel caso non sia trovata corrispondenza tra il campo della fonte dati associata al GridView e i valori dell'item della DropDownList, questo viene memorizzato nel campo OccasionalField.
protected override void OnDataBindField(object sender, EventArgs e) { //casto l'oggetto che a gererato l'evento ad un generico riferimento a Control Control _control = (Control)sender; DropDownList _dropDownList = sender as DropDownList; DataControlFieldCell _dataControlFieldCell = sender as DataControlFieldCell; //controllo se è necessatio encodare i dati bool encode = (SupportsHtmlEncode && HtmlEncode) && (sender is TableCell); //estraggo il volore _occasionalOldValue = this.GetValue(_control.NamingContainer); //se il sender è una DropDownList if (_dropDownList != null) { //recupero l'idice del item usando come chiave di ricerca il valore recuperato dallo sorgente dati int _index = _dropDownList.Items.IndexOf(_dropDownList.Items.FindByValue(_occasionalOldValue.ToString())); //se l'intem è presente nella fonte dati if (_index > -1) _occasionalOldValue = null; //imposto l'indice selezionato _dropDownList.SelectedIndex = _index; } //se il sender è una cella con dati else if (_dataControlFieldCell != null) { if (this.DesignMode) _dataControlFieldCell.Text = "abc"; else //formatto il valore _dataControlFieldCell.Text = FormatDataValue(_occasionalOldValue, encode); } }
Infine non rimane che eseguire l'override del metodo ExtractValuesFromCell allo scopo di recuperare il valore selezionato dalla DropDownList:
public override void ExtractValuesFromCell(System.Collections.Specialized.IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly) { //se la DropDownList è stata aggiunta if (cell.Controls.Count > 0) { //recupero il riferimento DropDownList _dropDownList = cell.Controls[0] as DropDownList; if (_dropDownList != null) { // recupero il valore (siaprecedente che attuale) object _dataField = _occasionalOldValue == null ? _dropDownList.SelectedValue : _occasionalOldValue; //l'aggiungo alla collezione dei parametri if (dictionary.Contains(DataField)) { dictionary[DataField] = _dataField; } else { dictionary.Add(DataField, _dataField); } } } else { base.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly); } }
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.