Actualité Tutoriels Liens contact dotnet-tech.com - Home - Tutoriels techniques avec code source Dotnet-tech.com : Les site sur les technologies .Net

Le MenuControl : contrôle riche

(Avec code source à télécharger)

Mis à jour le 15/09/2004
Par Boris Muller


Droit de diffusion:
L'ensemble ou partie de ce document ainsi que le code mis à disposition, ne peut être diffusé sur d'autres sites Web sans l'autorisation préalable de son créateur.

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   

  1. Définir et créer la classe MenuControl
  2. Créer la classe Item : MenuControlItem
  3. Ajouter le mécanisme de template .
  4. Définir et créer le mécanisme de liaison aux données
  5. 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