Introduction
Comment faire un controle riche permettant d’afficher un menu à plusieurs niveaux, en
utilisant les évènements, le databinding et les templates.
Connaître au préalable
Delegate et évènements
Le databinding
Les templated controles
Objectif
Définir le code source html pour
chacun des niveaux de l’arborescence, dans le gabarit.
Définir autant de niveau
différent que l’on souhaite sans modifier le contrôle.
Utiliser une source de donnée de
type datatable ou icollection
Modifier les éléments
crées
à la volée.
Hypothèse
La source de donnée sera déjà triè. On supposera que chaque élément de la source de donné est un noeud et qu’il est fils du précédent si l’identifiant de son père (idparent) est égal à
l’id de l’élément précédent.
Les différentes étapes
-
Définir et créer la classe
MenuControl
-
Créer la classe Item :
MenuControlItem
-
Ajouter le mécanisme de
template
.
-
Définir et créer le mécanisme de liaison aux données
-
Créer le gabarit et le code
behind
l’utilisant
Définir et créer la classe MenuControl
Créer une
nouvelle classe, la nommer MenuControl.
Hériter de
UserControl, pour bénéficier de l’ensemble des fonctionnalités
implémentés
pour cette classe.
Ajouter l’interface INamingContainer, afin de permettre à cette classe de définir un
namespace dans lequel chacun des contrôles crée aura un ClientID unique.
Voici le code source de ce contrôle.
///
<summary>
///
Summary description for
MenuControl
.
///
</summary>
public
class
MenuControl
:
UserControl,
INamingContainer
{
}
Créer la classe Item :
MenuControlItem
Il nous
faut pouvoir définir pour chaque niveau de l’arborescence:
-
le text pour afficher un libellé
-
l’image si image il faut afficher à la place du libellé
-
une url vers laquelle rediriger
-
un identifiant unique
-
l’identifiant parent pour établir la relation
père-fils.
-
le rang du contrôle
On aura besoin aussi plus tard de pouvoir :
-
y retrouver le conteneur interne sur lequel ajouter les
niveaux fils : Container
-
y ajouter l’objet provenant de la source de donnée
auquel est bindé le contrôle : DataItem
Code source :
///
<summary>
///
Represents
an item in the
MenuControl
control
///
</summary>
public
class
MenuControlItem
:
WebControl
,
INamingContainer
{
#region
Properties
///
<summary>
///
Gets or sets the text value for the control.
///
</summary>
public
string
Text
{
get
{
return
text;
}
set
{
text
=
value
;
}
}
private
string
text =
""
;
///
<summary>
///
Gets or sets the image value for the control.
///
</summary>
public
string
Image
{
get
{
return
image;
}
set
{
image
=
value
;
}
}
private
string
image =
""
;
///
<summary>
///
Gets or sets the rank value for the
control[
value
> 0].
///
</
summary
>
public
Int32 Rank
{
get
{
return
rank;
}
set
{
if
(
value
< 0)
throw
new
IndexOutOfRangeException
(
"Index
of a
MenuControlItem
can not be less than 0."
);
rank
=
value
;
}
}
private
Int32 rank = 0;
///
<
summary
>
///
Gets or sets the name of the inner container for the control.
///
</
summary
>
public
string
ContainerName
{
get
{
return
containerName;
}
set
{
containerName
=
value
;
}
}
private
string
containerName
=
""
;
///
<summary>
///
Gets
the inner container for the
control - if any.
///
</
summary
>
public
HtmlControl Container
{
get
{
return
(
HtmlControl
)
this
.FindControl
(
this
.ContainerName
);
}
}
///
<
summary
>
///
Gets or sets the
dataitem
bound to the
control.
///
</summary>
public
object
DataItem
{
get
{
return
dataItem
;
}
set
{
dataItem
=
value
;
}
}
private
object
dataItem
=
null
;
///
<summary>
///
Gets or sets the
url
value for the control
///
</summary>
public
string
Url
{
get
{
return
url
;
}
set
{
url
=
value
;
}
}
private
string
url =
""
;
#endregion
}
Ajouter le mécanisme de template
On voudrait permettre à l’utilisateur :
1.
de définir le code html de chaque niveau de
l’arborescence dans le gabarit
2.
de créer autant de modèle différent, qu’il aura de
niveau d’arborescence.
Pour le premier point il faut :
-
ajouter la propriété ItemTemplate – de type Itemplate -
à notre classe, pour recevoir les templates définis dans le gabarit
-
placer l’attribut TemplateContainer sur cette propriété
afin de caractèriser le type de template – ici : MenuControlItem.
-
ajouter à la classe MenuControl l’attribut
ParseChildren(
true
), afin que le lien entre les templates
définit dans le gabarit et l’attribut ItemTemplate de la classe se fasse.
Pour le second point :
- le
set
de la propriété ItemTemplate stockera non pas l’Itemplate obtenu dans une variable mais
plutôt dans une collection.
Voici le code source de la classe MenuControl modifié
///
<summary>
///
Summary description for
MenuControl
.
///
</summary>
[
ParseChildren
(
true
)]
public
class
MenuControl
:
UserControl,
INamingContainer
{
#region
Properties
public
event
MenuControlEventHandler
ItemDataBound
;
///
<summary>
///
Sets
the template for each level
of the control
///
</summary>
[
TemplateContainer
(
typeof
(
MenuControlItem
))]
public
ITemplate
ItemTemplate
{
set
{
if
(
itemTemplates
==
null
)
itemTemplates
=
new
ArrayList
();
itemTemplates.Add
(
value
);
}
}
private
ArrayList
itemTemplates
=
null
;
}
Définir et créer le
mécanisme de liaison aux données
On voudrait permettre à l’utilisateur du contrôle de réagir
à la création d’un élément :
-
définir une classe MenuControlEventArgs par laquel sera
transmis le contrôle crée
-
définir le delegate MenuControlEventHandler
-
&n