11

Sto creando un controllo server che lega essenzialmente due elenchi a discesa, uno per paese e uno per stato, e aggiorna il menu a discesa stato sull'evento selezionatoindexchanged. Tuttavia, non sta postando indietro. Qualche idea, perché? I punti bonus per avvolgendoli in un UpdatePanel (avendo problemi di rendering, forse perché io non ho una pagina di riferimento?)ASP.NET/C#: DropDownList SelectedIndexChanged nel controllo del server non attivo

Ecco quello che ho (con alcune cose l'accesso ai dati in più spogliato fuori):

public class StateProv : WebControl 
{ 
    public string SelectedCountry; 
    public string SelectedState; 

    private DropDownList ddlCountries = new DropDownList(); 
    private DropDownList ddlStates = new DropDownList(); 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     IList<Country> countries = GetCountryList(); 
     IList<State> states = new List<State>(); 

     if (SelectedCountry != null && SelectedCountry != "") 
     { 
      states = GetStateList(GetCountryByShortName(SelectedCountry).CountryShortName); 
     } 
     else 
     { 
      states.Add(new State { CountryId = 0, Id = 0, StateLabelName = "No states available", StateLongName = "No states available", StateShortName = "" }); 
     } 

     ddlCountries.DataSource = countries; 
     ddlCountries.DataTextField = "CountryLongName"; 
     ddlCountries.DataValueField = "CountryShortName"; 
     ddlCountries.SelectedIndexChanged += new EventHandler(ddlCountry_SelectedIndexChanged); 
     ddlCountries.AutoPostBack = true; 

     ddlStates.DataSource = states; 
     ddlStates.DataTextField = "StateLongName"; 
     ddlStates.DataTextField = "StateShortName"; 

     ddlCountries.DataBind(); 
     ddlStates.DataBind(); 

     if (!string.IsNullOrEmpty(SelectedCountry)) 
     { 
      ddlCountries.SelectedValue = SelectedCountry; 

      if (!string.IsNullOrEmpty(SelectedState)) 
      { 
       ddlStates.SelectedValue = SelectedState; 
      } 
     }    
    } 


    protected override void RenderContents(HtmlTextWriter output) 
    { 
     ddlCountries.RenderControl(output); 
     ddlStates.RenderControl(output); 
    } 

    private IList<Country> GetCountryList() 
    { 
     //return stuff 
    } 

    private IList<State> GetStateList(Country country) 
    { 
     //return stuff 
    } 

    private IList<State> GetStateList(string countryAbbrev) 
    { 
     Country country = GetCountryByShortName(countryAbbrev); 
     return GetStateList(country); 
    } 

    private Country GetCountryByShortName(string countryAbbrev) 
    { 
     IList<Country> list = dataAccess.RetrieveQuery<Country>(); 
     //return stuff 
    } 

    private IList<State> GetAllStates() 
    { 
     //return stuff 
    } 

    protected void ddlCountry_SelectedIndexChanged(object sender, EventArgs e) 
    { 
     IList<State> states = GetStateList(GetCountryList()[((DropDownList)sender).SelectedIndex]); 
     ddlStates.DataSource = states; 
     ddlStates.DataBind(); 
    } 
} 

Modifica: Viewstate si trova sulla pagina e altri controlli sulla pagina eseguono correttamente i postback, ma non questo.

+0

Probabilmente non conta come una risposta, ma l'Ajax Control Toolkit offre quello che vuoi già all'interno di un pannello di aggiornamento: http://www.asp.net/AJAX/AjaxControlToolkit/Samples/CascadingDropDown/CascadingDropDown.aspx – Sean

+0

Sì; Ho giurato per sempre l'ACT per sempre. Immondizia assoluta IMO; In realtà sto costruendo un sostituto per il mio progetto, dal momento che solo il controllo CCD può funzionare con un servizio Web, con altre implicazioni. –

risposta

5

Viewstate è attivato?

Edit: Forse si dovrebbe riconsiderare sovrascrivendo la funzione di rendering

protected override void RenderContents(HtmlTextWriter output) 
    { 
     ddlCountries.RenderControl(output); 
     ddlStates.RenderControl(output); 
    } 

e invece aggiungere i DropDownList per il controllo e il rendering del controllo utilizzando i RenderContents predefiniti.

Edit: Vedi la risposta di Dennis, che ho accennato nel mio precedente commento:

Controls.Add (ddlCountries); 
Controls.Add (ddlStates); 
+0

Sembra promettente. Se ViewState è disattivato (nel menu a discesa o in uno dei suoi genitori, fino alla pagina), l'evento non viene attivato. (Dovrebbe postback però ...) – teedyay

+0

Viewstate è sulla pagina su cui si trova il controllo. C'è qualcosa di specifico in questo controllo, in questo file .cs, che devo fare? –

+0

un modo rapido per controllare è guardare il codice sorgente e vedere se qualcosa è memorizzato in viewstate –

3

È necessario impostare AutoPostBack su true per il Paese DropDownList.

protected override void OnLoad(EventArgs e) 
{ 
    // base stuff 

    ddlCountries.AutoPostBack = true; 

    // other stuff 
} 

Modifica

ho perso che aveva fatto questo. In tal caso è necessario verificare che ViewState sia abilitato.

+0

La sua riga "ddlCountries.AutoPostBack = true;" non farlo? –

0

In primo luogo, vorrei chiarire qualcosa. Si tratta di un postback (ritorno al server) che non si verifica mai, o si verifica il postback, ma non entra mai nel gestore di eventi ddlCountry_SelectedIndexChanged?

Non sono sicuro del caso in cui ci si trova, ma se è il secondo caso, posso offrire qualche suggerimento. Se è il primo caso, la seguente è FYI.

Per il secondo caso (gestore di eventi non si attiva, anche se richiesta fatta), si consiglia di provare i seguenti suggerimenti:

  1. interrogare il Request.Params [ddlCountries.UniqueID] e vedere se ha valore . In caso affermativo, licenzia manualmente il gestore di eventi.
  2. Fintanto che lo stato di visualizzazione è attivo, si vincolano solo i dati dell'elenco quando non è un postback.
  3. Se lo stato di visualizzazione deve essere disattivato, inserire i dati dell'elenco associare in OnInit anziché OnLoad.

Attenzione che quando si chiama Control.DataBind(), lo stato di visualizzazione e le informazioni di postback non sarebbero più disponibili dal controllo. Nel caso in cui lo stato della vista sia attivo, tra il postback, i valori di DropDownList verranno mantenuti intatti (l'elenco non deve essere rimbalzato). Se si invia un altro DataBind in OnLoad, si cancellano i suoi dati sullo stato di visualizzazione e l'evento SelectedIndexChanged non viene mai generato.

Nel caso in cui lo stato di visualizzazione sia disattivato, non è possibile scegliere di ripetere l'elenco ogni volta. Quando si verifica un postback, ci sono chiamate interne ASP.NET per popolare il valore da Request.Params ai controlli appropriati, e ho il sospetto che si verifichi al momento tra OnInit e OnLoad. In questo caso, il ripristino dei valori di elenco in OnInit consentirà al sistema di attivare correttamente gli eventi.

Grazie per il vostro tempo a leggere questo, e dare il benvenuto a tutti per correggere se ho torto.

+0

Non sta colpendo affatto il server quando cambio la voce di elenco selezionata. Grazie comunque; questo è un altro problema che ho dovuto risolvere in altre aree ed è una buona informazione. –

+0

Vedo; quindi penso che la risposta di Dennis Myren sarà probabilmente quella corretta: i due DropDownList non sono nella struttura di controllo, quindi anche se sono correttamente renderizzati, i meccanismi di gestione degli eventi ASP.NET semplicemente non potevano vedere l'esistenza dal livello di pagina, quindi nessun evento è licenziato. –

4

Non riesco a vedere che stai aggiungendo questi controlli alla gerarchia di controllo. Prova:

Controls.Add (ddlCountries); 
Controls.Add (ddlStates); 

Eventi non saranno invocati a meno che il controllo è parte della gerarchia di controllo.

+0

Sì - e farlo in un evento precedente al caricamento (come ad esempio Init); altrimenti i controlli non saranno nel posto giusto quando il ViewState verrà ricaricato. – teedyay

+0

Sì, o preferibilmente in Override CreateChildControls – baretta

+0

Stava per dire la stessa cosa ... dovrebbero essere creati e aggiunti alla collezione Controls in CreateChildControls. Puoi anche eliminare l'override di rendering. – flatline

1

Ho avuto lo stesso problema ma ho aggirato impostando AutoPostBack su true e in un pannello di aggiornamento imposta il trigger sull'ID del controllo elenco a discesa e il nome dell'evento su SelectedIndexChanged, ad es.

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always" enableViewState="true"> 
     <Triggers> 
      <asp:AsyncPostBackTrigger ControlID="ddl1" EventName="SelectedIndexChanged" /> 
     </Triggers> 
     <ContentTemplate> 
      <asp:DropDownList ID="ddl1" runat="server" ClientIDMode="Static" OnSelectedIndexChanged="ddl1_SelectedIndexChanged" AutoPostBack="true" ViewStateMode="Enabled"> 
       <asp:ListItem Text="--Please select a item--" Value="0" /> 
      </asp:DropDownList> 
     </ContentTemplate> 
    </asp:UpdatePanel>