6

J'ai suivi l'article TRULLY Understanding ViewState (grand article btw) et remplir ma liste déroulante fonctionne très bien. J'ai même configuré un événement OnSelectedIndexChange qui se déclenche presque aussi bien.DropDownList OnSelectedIndexChange à 0e index sans ViewState

Le problème que j'ai trouvé est l'événement SelectedIndexChanged ne se déclenchera pas lors de la sélection de l'index 0e. Il fait tous les autres fois cependant.

Voici quelques code:

<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false" 
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" /> 


protected override void OnInit(EventArgs e) 
{ 
    this.DropDownList1.DataTextField = "Text"; 
    this.DropDownList1.DataValueField = "Value"; 
    this.DropDownList1.DataSource = fillQueueDropDown(); 
    this.DropDownList1.DataBind(); 

    base.OnInit(e); 
} 

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) 
{ 
    OnSelectedQueueChanged(e); 
} 

public void OnSelectedQueueChanged(EventArgs e) 
    { 
     // Do stuff. 
    } 

public event EventHandler queueNamesChangedEvent; 
public void OnSelectedQueueChanged(EventArgs e) 
    { 
     if (queueNamesChangedEvent != null) 
      queueNamesChangedEvent(this, e); 
    } 

Je suppose que je peux faire un certain type de contrôle dans la méthode Page_Load:

if(ViewState["selectedIndexChangedFlag"] != 1) 
     // raise OnSelectedChange event 

Ou est-il quelque chose que je peut configuration dans la méthode OnInit() où je reconfigure ces données chaque fois que je peux faire? Voyez, mon EventHander personnalisé déclenche un événement qui est attrapé par une page parent dans laquelle ce contrôle réside, de sorte que le parent puisse prendre une certaine action en utilisant la nouvelle valeur sélectionnée. Et cela fonctionne actuellement pour tous les cas où l'index sélectionné> 0.

Je crée une propriété dans ce contrôle qui contient l'index sélectionné le plus récemment, auquel cas ma page parente peut agir sur cette valeur de propriété sur chaque Page_Load. .. ne sais pas.

Ouvert aux suggestions. Ou comment forcer cet événement SelectedIndexChanged à se déclencher pour cette sélection d'index 0e.

Répondre

5

Mon objectif avec la désactivation de ViewState sur cette liste déroulante est de minimiser la taille de ViewState pour la page. Le problème que j'ai eu avec seulement if (! Page.IsPostBack) {... DataBind() ...}, c'est que lorsque vous sélectionnez un élément pour la première fois, et que la page se recharge, mon drop La liste descendante devient vide.

Ce que j'ai fini par faire était de créer une autre propriété sur ce contrôle, LastIndex. Lorsque l'événement OnSelectedIndexChanged se déclenche, je mets à jour la valeur LastIndex. Dans le Page_Load, je compare les valeurs d'index Current et Last, si elles sont différentes, puis déclenche un événement Index modifié.

public int SelectedValue{ 
     get { return this.DropDownList1.SelectedItem.Value; } 
    } 

    public int LastIndex{ 
     get { return this.ViewState["lastIndex"] == null ? -1 : (int)this.ViewState["lastIndex"]; } 
     set { this.ViewState["lastIndex"] = value; } 
    } 

    protected override void OnInit(EventArgs e){ 
     base.OnInit(e); 
     this.DropDownList1.DataTextField = "Text"; 
     this.DropDownList1.DataValueField = "Value"; 
     this.DropDownList1.DataSource = fillQueueDropDown(); 
     this.DropDownList1.DataBind(); 
    } 

    protected void Page_Load(object sender, EventArgs e){ 
     if (this.LastIndex != this.SelectedValue) 
      this.OnSelectedQueueChanged(new EventArgs()); 
    } 

    private ListItemCollection fillQueueDropDown(){...} 

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){ 
     OnSelectedQueueChanged(e); 
     this.LastIndex = this.SelectedValue; 
    } 

    public event EventHandler queueNamesChangedEvent; 
    public void OnSelectedQueueChanged(EventArgs e){ 
     if (queueNamesChangedEvent != null) 
      queueNamesChangedEvent(this, e); 
    } 

Vous avez raison. Les données sont rechargées et reliées dans la phase OnInit. Ensuite, le ViewState est restauré (et lorsque le 0e index est restauré), lorsque nous arrivons finalement à la phase Events, le contrôle ne détecte pas la modification.

Je ne suis pas sûr que ce soit l'itinéraire le plus élégant, mais il fonctionne bien jusqu'à présent.

Alors je trouve cela dans les msdn docs pour IPostBackDataHandler:

public virtual bool LoadPostData(string postDataKey, 
    NameValueCollection postCollection) { 

    String presentValue = Text; 
    String postedValue = postCollection[postDataKey]; 

    if (presentValue == null || !presentValue.Equals(postedValue)) { 
     Text = postedValue; 
     return true; 
    } 

    return false; 
    } 

Puisque la valeur actuelle est la même que la valeur à changé, l'événement ne se déclenche pas.

+1

+1 Très bien - c'est une excellente façon de le faire sans ViewState! Désolé, je n'ai pas remarqué que vous ne vouliez pas de ViewState - je vais lire la question plus attentivement la prochaine fois. –

+1

Merci pour votre solution initiale, cela a vraiment aidé à faire la lumière sur l'ordre des choses. Je suppose que je ne connais pas le cycle de vie de la page asp.net aussi bien que je pensais. –

8

Le problème est que vous chargez les données à chaque fois et que cela réinitialise l'index sélectionné. Imaginez ceci est votre menu déroulant:

zero [selected] 
one 
two 

Puis dans le client vous modifiez l'index sélectionné:

zero 
one [selected] 
two 

Cela remplit l'entrée cachée __EVENTARGUMENT avec votre nouvel indice (1) et l'entrée cachée __EVENTTARGET avec le id de votre liste déroulante. Maintenant, le code côté serveur démarre et Actualise données:

zero [selected] 
one 
two 

« zéro » est la valeur sélectionnée parce que c'est la valeur par défaut lorsque les données sont chargées. Ensuite ASP.NET recherche __EVENTTARGET et __EVENTARGUMENT dans le Request et trouve votre id de liste déroulante et trouve le nouvel index (1). Maintenant, votre menu déroulant ressemble à ceci:

zero 
one [selected] 
two 

Comme l'indice a changé, le menu déroulant soulève son événement SelectedIndexChanged indiquant que l'indice a changé. Évidemment, c'est la partie qui fonctionne, voyons maintenant pourquoi la sélection du premier élément de la liste ne déclenche pas l'événement. Maintenant, disons que nous avons toujours la liste déroulante dans l'état où elle était juste (avec "un" étant sélectionné et l'index sélectionné de 1). Que se passe-t-il lorsque nous sélectionnons le premier élément de la liste sur le client?

__EVENTTARGET et __EVENTARGUMENT sont remplis avec le id de la liste déroulante et le nouvel index (0). Ensuite, le serveur charge les données dans la liste déroulante et le menu déroulant ressemble maintenant à nouveau:

zero [selected] 
one 
two 

Notez que depuis que vous avez rechargé les données avant les événements ont tiré l'indice est déjà réglé sur 0, car c'est la valeur par défaut . Maintenant, lorsque votre événement se déclenche et que l'index sélectionné de la liste déroulante est défini sur 0, la liste déroulante ne voit pas cela comme un changement puisque l'index sélectionné (pour autant qu'il le sache) n'a pas changé.

Voici comment résoudre le problème:

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

    if (!Page.IsPostBack) 
    { 
     this.DropDownList1.DataTextField = "Text"; 
     this.DropDownList1.DataValueField = "Value"; 
     this.DropDownList1.DataSource = fillQueueDropDown(); 
     this.DropDownList1.DataBind(); 
    }  
} 

Qu'est-ce que cela va faire est de ne charger que les données dans le menu déroulant si la page n'est pas une publication. Cela signifie que ViewState conservera les données pour vous ainsi que l'index sélectionné afin que lorsque vous publiez, la liste déroulante compare le nouvel index à l'index que vous avez vu dans le client.

+0

Une très bonne explication! –