FAQ ASP.NET/VB.NET
FAQ ASP.NET/VB.NETConsultez toutes les FAQ
Nombre d'auteurs : 38, nombre de questions : 369, dernière mise à jour : 16 juin 2021
- Ma dropdownlist est bien remplie, mais quand je sélectionne un item, c'est toujours la première valeur de la liste qui est retournée
- La propriété SelectedValue d'une DropDownList me renvoi Nothing, pourquoi?
- Comment ajouter d'autres éléments que ceux d'une liste ?
- Comment insérer un élément dans une DropDownList à un emplacement donné ?
- J'ai déclaré l'attribut OnChange sur ma DropDownList mais rien ne se passe lors d'un changement de valeur. Pourquoi ?
- Parfois ma dropdownlist ne lève pas l'événement OnSelectedIndexChanged ou OnTextChanged, même si AutoPostBack="true", que faire ?
- Comment lever l'événement SelectedIndexChanged pour des DropDownList dans un Repeater lorsque le Viewstate est à false ?
- Comment désactiver une DropDownList après qu'un item ait été sélectionné dans cette liste?
- Comment colorer différemment chaque Item d'une DropDownList?
- Comment faire pour que ma dropdownlist ne cause un postback que sous certaines conditions ?
Ce problème est trés récurent. Dans 99% des cas le problème vient du postback :
Si vous remplissez votre dropdownlist dans le "Page_Load" de votre page, le code correct est :
Private
Sub
Page_Load
(
ByVal
sender As
System.Object
, ByVal
e As
System.EventArgs
) Handles
MyBase
.Load
If
not
Page.IsPostBack
Then
'code pour remplir la dropdownlist
End
If
End
Sub
L'erreur fréquement comise est d'oublier le "If not page.IsPostBack then" quand vous sélectionnez un objet de la dropdownlist, la page se recharge en faisant un postback, donc repasse par le "Page_Load et reinitialise votre dropdownlist. On spécifie donc qu'il ne faut pas reinitialiser la dropdownlist en cas de PostBack et on récupèrera ainsi la valeur sélectionnée.
Il arrive fréquemment que l'on remplisse une DropDownList avec les valeurs qui
sont à afficher. Par contre, les valeurs sont souvent oubliées lors de cette initialisation.
Si l'initialisation se fait à l'aide d'un DataSet, rien de plus simple, il suffit de spécifier quel est le champ qui permettra de récupérer la valeur:
NomDropDownList.DataSource
=
DbTemplate.GetCategories
NomDropDownList.DataTextField
=
"champ_a_afficher"
NomDropDownList.DataValueField
=
"champ_valeur"
NomDropDownList.DataBind
Si l'initialisation se fait par l'ajout manuel d'Items, il suffit de créer des Items en spécifiant les deux valeurs.
Dim
li As
ListItem =
New
ListItem
li.Text
=
"texte"
li.Value
=
"valeur"
NomDropDownList.Items.Add
(
li)
Vous pouvez ajouter un Item directement en utilisant Items.Add. Le premier paramètre correspond à l'emplacement (en l'occurrence 0) :
ddl.Items.insert
(
0
,"mon texte"
)
Cependant, cette solution ne fait qu'afficher un texte. Si vous souhaitez passer un texte ainsi que la valeur correspondante, il est nécessaire d'utiliser un objet ListItem :
Dim
li as
ListItem=
New
ListItem
(
"mon texte"
, "ma valeur"
)
ddl.Items.Insert
(
0
, li)
Pour ajouter un élément à la collection Items d'une DropDownList il existe la fonction Add, mais celle-ci l'ajoute à la fin. Si on ne veut pas l'ajouter à la fin, il faut utiliser la fonction Insert :
MyDropDownList.Items.Insert
(
0
, new
ListItem
(
"2 CV"
, "Voiture"
))
Le code ci-dessus insérera l'élément "2 CV" et sa valeur "Voiture" à la position 0 de collection Items de la DropDownList
Lien : Fonction Insert
L'erreur la plus fréquente est d'oublier de mettre à true la propriété AutoPostBack. Ce qui donne:
<
asp:
DropDownList runat=
server id=
IdDdl AutoPostBack=
true
>...</
asp:
DropDownList>
Si la propriété est à true, lorsque l'on sélectionne une autre valeur, la page est renvoyée
au serveur.
Attention de ne pas réinitialiser la valeur sélectionnée dans le Page_Load.
Cela peut arriver si vous avez positionné EnableViewState à false sur votre page. Certaines stratégies d'entreprises prônent de ne pas utiliser le viewstate, pour certaines raisons compréhensibles que je ne détaillerai pas ici, et encouragent à récupérer les valeurs dans tout postback.
Mais cela pose un problème lorsqu'on veut utiliser les événements accessibles lorsqu'autopostback vaut true.
Imaginons une page toute simple (du code a été omis pour plus de clarté) où EnableViewState vaut false :
<
%@ Page Language=
"vb"
EnableViewState=
"false"
AutoEventWireup=
"false"
CodeBehind=
"Default.aspx.cs"
Inherits
=
"testDropdown.Default"
%>
<
asp:DropDownList ID=
"myDropDown"
runat=
"server"
AutoPostBack=
"true"
OnSelectedIndexChanged=
"ItemChange"
>
<
asp:ListItem Value=
"valeur1"
Text
=
"valeur1"
/>
<
asp:ListItem Value=
"valeur2"
Text
=
"valeur2"
/>
<
asp:ListItem Value=
"valeur3"
Text
=
"valeur3"
/>
</
asp:DropDownList>
<
asp:Label ID=
"myLabel"
runat=
"server"
/>
et dans le code behind
Protected
Sub
ItemChange
(
ByVal
sender As
Object
, ByVal
e As
EventArgs)
myLabel.Text
=
String
.Format
(
"Valeur selectionnée : {0}"
, sender.SelectedValue
)
End
Sub
Si l'on sélectionne les valeurs 2 ou 3, le texte est correctement affiché car on est passé correctement dans l'événement. Par contre, si on rebascule sur la valeur 1, rien n'est affiché, on ne passe pas dans l'événement.
En effet, comme le viewstate n'est pas utilisé, asp.net croit que c'est la valeur 1 qui est sélectionnée, et quand on la resélectionne après un premier changement, il en déduit que la valeur n'a pas changée, donc, il ne lève pas l'événement (le brigand).
La solution est donc de lever l'événement nous même, en surchargeant le OnLoad.
Protected
Overrides
Sub
OnLoad
(
ByVal
e As
System.EventArgs
)
If
IsPostBack Then
' on lève l'évenement si le postback a été déclenché par notre dropdown
Dim
ctlName As
String
=
Request
.Params.Get
(
"__EVENTTARGET"
)
If
Not
String
.IsNullOrEmpty
(
ctlName) Then
If
ctlName.Contains
(
myDropDown.ID
) Then
ItemChange
(
myDropDown, New
EventArgs
(
))
End
If
End
If
End
If
MyBase
.OnLoad
(
e)
End
Sub
Protected
Sub
ItemChange
(
ByVal
sender As
Object
, ByVal
e As
EventArgs)
myLabel.Text
=
String
.Format
(
"Valeur selectionnée : {0}"
, sender.SelectedValue
)
End
Sub
Et au final, nous n'avons plus besoin de définir OnSelectedIndexChanged="ItemChange" comme attribut de <asp:DropDownList>
NB : Si on veut, il est bien sur possible de changer le prototype de la méthode ItemChange, vu qu'elle n'est plus levée par Asp.Net
Private
Sub
ItemChange
(
ByVal
list As
DropDownList, ByVal
e As
EventArgs)
End
Sub
Comment faire pour lever un événement de changement lorsqu'une dropdown se repete X fois dans un repeater ?
Pour ce faire, nous allons déjà construire notre repeater.
Dans la page, on aura par exemple notre repeater, une dropdownlist par item et un label en dehors de ce repeater pour afficher la sélection :
<
asp:Repeater runat=
"server"
OnItemCreated=
"ItemCreated"
ID=
"MonRepeater"
>
<
ItemTemplate>
<
asp:DropDownList runat=
"server"
ID=
"LaList"
AutoPostBack=
"true"
/>
</
ItemTemplate>
</
asp:Repeater>
<
asp:Label runat=
"server"
ID=
"LeLabel"
/>
Pour initialiser notre repeater, rien de tel qu'une bonne liste de liste
Protected
Overrides
Sub
OnInit
(
ByVal
e As
System.EventArgs
)
EnableViewState =
False
Dim
list As
New
List
(
Of
List
(
Of
String
))
Dim
list1 As
New
List
(
Of
String
)
list1.Add
(
"abc"
)
list1.Add
(
"def"
)
list1.Add
(
"ghi"
)
Dim
list2 As
New
List
(
Of
String
)
list2.Add
(
"123"
)
list2.Add
(
"456"
)
list2.Add
(
"789"
)
list.Add
(
list1)
list.Add
(
list2)
MonRepeater.DataSource
=
list
MonRepeater.DataBind
(
)
MyBase
.OnInit
(
e)
End
Sub
Pour bien montrer qu'on ne se servira pas du viewstate, on le met explicitement à false dans le OnInit
Et dans l'événement du ItemCreated, on construit la dropdown à partir de la liste :
Protected
Sub
ItemCreated
(
ByVal
sender As
Object
, ByVal
e As
RepeaterItemEventArgs)
Dim
list As
DropDownList =
e.Item.FindControl
(
"LaList"
)
list.Items.Add
(
"choisir ..."
)
For
Each
element As
String
In
e.Item.DataItem
list.Items.Add
(
element)
Next
End
Sub
Si on execute la page, on a donc 2 dropdownlist remplies respectivement des valeurs "choisir ...", "abc", "def", "ghi" et "choisir ...", "123", "456", "789".
Passons maintenant à la propagation de l'événement, toujours en surchargeant le OnLoad, juste après le base.OnLoad :
Protected
Overrides
Sub
OnLoad
(
ByVal
e As
System.EventArgs
)
MyBase
.OnLoad
(
e)
If
IsPostBack Then
Dim
ctlName As
String
=
Request
.Params.Get
(
"__EVENTTARGET"
)
If
Not
String
.IsNullOrEmpty
(
ctlName) Then
' on va chercher la dropdown qui a déclenché le postback dans __EVENTTARGET
For
Each
item As
RepeaterItem In
MonRepeater.Items
Dim
clientId As
String
=
item.ClientID
' utilisé pour avoir la propriété ID, sinon elle vaudra null
Dim
currentDropDown As
DropDownList =
item.FindControl
(
"LaList"
)
Dim
dropDownName As
String
=
String
.Format
(
"{0}${1}"
, item.ID
, currentDropDown.ID
)
If
ctlName.Contains
(
dropDownName) Then
ItemChange
(
currentDropDown, New
EventArgs
(
))
End
If
Next
End
If
End
If
End
Sub
Le principe est de parcourir les items du repeater et de concatener l'id de l'item à celle de la dropdownlist en mettant un $ entre les deux ; c'est grâce à ces deux valeurs qu'on pourra identifier de manière unique la dropdown qui a déclenché le postback.
ctlName vaudra "MonRepeater$ctl00$LaList"
et dropDownName vaudra "ctl00$LaList"
Une fois la dropdown identifiée, il n'y a plus qu'à simuler l'événement ItemChange, qui ici, nous affichera le résultat choisi dans le label
Sub
ItemChange
(
ByVal
list As
DropDownList, ByVal
args As
EventArgs)
LeLabel.Text
=
list.SelectedValue
End
Sub
Voilà pour la dropdownlist dans un repeater
NB : ici, j'ai utilisé une astuce pour récupérer l'id de l'item du repeater. En effet, dans le OnLoad il vaut null, je force la génération du ClientId pour pouvoir récupérer l'ID.
Soit une DropDownList:
<asp:
DropDownList id
=
"ddl"
runat
=
"server"
>
<asp:
ListItem Value
=
"1"
>
Choix 1</asp
:
ListItem>
<asp:
ListItem Value
=
"2"
>
Choix 2</asp
:
ListItem>
<asp:
ListItem Value
=
"3"
>
Choix 3</asp
:
ListItem>
</asp
:
DropDownList>
Ensuite, dans le code:
ddl.
Attributes.
Add
(
"onchange"
,
"this.disabled=true;"
)
ou directement dans le .aspx:
Soit une liste déroulante déclarée en html de telle manière (ou une DropDownList qui est l'équivalent en asp.NET):
<SELECT id
=
"Couleur"
runat
=
"server"
name
=
"Couleur"
></SELECT>
Cette liste a pour but d'afficher la liste des couleurs possibles avec la couleur en fond de chaque item.
Dans le code de traitement, il suffit alors d'inclure
Imports
System.Reflection
et enfin d'ajouter les différents Items à la liste.
For
Each
col As
FieldInfo In
GetType
(
KnownColor).GetFields
If
col.FieldType
=
GetType
(
KnownColor) Then
Couleur.Items.Add
(
New
ListItem
(
col.Name
, col.Name
))
End
If
Next
Dim
i As
Integer
=
0
While
i <
Couleur.Items.Count
Couleur.Items
(
i).Attributes.Add
(
"style"
, "background-color:"
+
Couleur.Items
(
i).Text
)
System.Math.Min
(
System.Threading.Interlocked.Increment
(
i),i-
1
)
End
While
On peut imaginer d'autres utilisations telles mettre en rouge la liste des factures non payées et en vert celles qui sont payées dans une application de gestion de factures.
On met la propriété AutoPostBack à true. Le principe est d'empecher la publication du postback en modifiant le javascript de l'attribut onchange pour qu'il renvoit false lorsque les conditions ne sont pas respectées.
myDropDownList.AutoPostBack
=
true
myDropDownList.Attributes
["onchange"
] =
"if("
+
myDropDownList.ClientID
+
".selectedIndex != "
+
myDropDownList.ClientID
+
".length-1) return false; else"
le code est completé lors de la génération de la page. Dans le code html généré, __doPostBack(...) sera automatiquement rajouté après le else (parce qu'on à mis le AutoPostBack = true).
Dans cet exemple, on envoit le formulaire uniquement lorsque c'est le dernier élément qui est sélectionné.