• 30 hours
  • Medium

Free online content available in this course.

Certificate of achievement available at the end this course

You can get support and mentoring from a private teacher via videoconference on this course.

Got it!

Last updated on 11/23/17

Afficher les vues

Log in or subscribe for free to enjoy all this course has to offer!

Alors les modèles bien faits, avec des superbes tests et des patterns qui déchirent, c’est bien. Mais ça, nos utilisateurs ils s’en moquent un peu. Ce qu’ils veulent eux, c’est que le site soit beau (et qu’il fonctionne bien sûr). En tous cas, la première chose qu’ils vont voir, ce sont nos pages HTML.
Dans le modèle MVC, l’affichage de ce que l’on voit est géré par le « V » (pour « vue »). Il va falloir être attentif si vous voulez faire plaisir à vos utilisateurs ! :) Vous pouvez appliquer tout ce que vous savez déjà sur la création d’interfaces à vos applications MVC. Comment ? C’est ce que nous allons voir dans ce chapitre sur les vues.

Afficher une vue

Nous avons vu que par convention, les vues se plaçaient dans le répertoire /Views, plus précisément dans un sous-répertoire correspondant au nom du contrôleur lié à la vue. Le nom de la vue est également, par convention, lié au nom de l’action du contrôleur.
Par exemple, une vue retournée par l’actionIndex  du contrôleurHome  se place dans le répertoire /Views/Home et s’appellera Index.cshtml.

Pour notre application fil-rouge, si nous voulons créer une page d’accueil accessible par exemple via l’adresse /, nous pouvons utiliser le routing par défaut et créer un contrôleur nomméHomeController  et créer une méthode Index qui renvoie simplement la vue par défaut.
Sauf que ça m’embête d’avoir de l’anglais dans mes URL… nous allons juste modifier la méthode de définitions des routes pour remplacerHome  parAccueil  :

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Accueil", action = "Index", id = UrlParameter.Optional }
    );
}

Maintenant, nous allons créer un simple contrôleur de base, directement par un clic droit > Ajouter contrôleur sur le répertoire Controllers , comme nous avons déjà fait. Appelez-le bien sûrAccueilController , de modèle contrôleur MVC vide. Cela nous permet d’avoir la simple méthode, générée par Visual Studio :

public ActionResult Index()
{
    return View();
}

qui nous revoie la vue par défaut lorsque l’action Index est invoquée. Pour l’invoquer justement, démarrez le projet ASP.NET MVC en appuyant sur F5.

Comme vous devez l’imaginer, étant donné que nous n’avons pas créé de vue, nous allons nous retrouver avec une erreur :

 

La vue « Index » ou son maître est introuvable, ou aucun moteur de vue ne prend en charge les emplacements où est effectuée la recherche. La recherche a porté sur les emplacements suivants :
~/Views/Accueil/Index.aspx
~/Views/Accueil/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/Accueil/Index.cshtml
~/Views/Accueil/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml

Nous retrouvons ici la fameuse convention évoquée précédemment. Étant donné que nous avons instancié le contrôleurAccueil  et sa méthodeIndex , et que ce contrôleur retourne la vue par défaut grâce à la méthodeView() , il cherche à trouver la vue située dans le répertoire Views/Accueil, s’appelant Index.aspx ou Index.ascx.

Il cherche ensuite la même chose dans le répertoire Views/Shared. Puis, il cherche dans ces mêmes répertoires les fichiers Index.cshtml ou Index.vbhtml. 

Ne trouvant rien, il lève une exception.

Et là, c’est à nous de jouer. Nous allons créer la vueIndex . J’en profite pour vous montrer une petite astuce pour créer une vue rapidement. Faites un clic droit dans la méthodeIndex  du contrôleurAccueil , nous pouvons directement créer la vue avec l’élément du menu contextuel « Ajouter une vue » :

Ajout d'une vue depuis le contrôleur
Ajout d'une vue depuis le contrôleur

Nous obtenons la fenêtre pré-remplie suivante :

Ajout de la vue
Ajout de la vue

Vous pouvez tout décocher pour créer une vue la plus simple possible et cliquer sur Ajouter. Et voilà, Visual Studio a créé tout seul la bonne vue et l’a placée au bon endroit en plus. Vous pouvez aller jeter un œil dans le répertoire Views, il y a bien un sous-répertoire Accueil et dedans un fichier Index.cshtml :

La nouvelle vue dans l'explorateur de solutions
La nouvelle vue dans l'explorateur de solutions

Notre vue est plutôt vide, rajoutons-lui un petit message, histoire de la différencier facilement :

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        Je suis la vue index
    </div>
</body>
</html>

Ici, en l’occurrence, le code illustrant cette vue pourra être :

<div>
    Je suis la vue index
</div>

Ceci simplement pour éviter de vous surcharger d’informations potentiellement inutiles à l’apprentissage du moment.
Redémarrons l’application web et nous nous retrouvons bien avec l’affichage de la vue :

Affichage de la vue Index
Affichage de la vue Index

Rappelez-vous, le choix de l’affichage de la vue Index est fait par le contrôleur. C’est l’instruction :

return View();

qui détermine le choix de la vue qui s’appelle comme l’action du contrôleur, en l’occurrenceIndex . Il faut savoir qu'ici cette instruction est équivalente à la suivante :

return View("Index");

où nous indiquons explicitement que nous souhaitons afficher la vueIndex . Cela veut dire que nous pouvons choisir d’afficher la vue que nous voulons. Créez par exemple une nouvelle vue dans le répertoire Views/Accueil et appelez-la Bonjour  :

Ajout d'une vue Bonjour
Ajout d'une vue Bonjour

Mettez un petit message pour la différencier :

<div>
    Je suis la vue Bonjour
</div>

Pour y accéder depuis la même action du contrôleur, il suffit d’utiliser le code suivant :

public ActionResult Index()
{
    return View("Bonjour");
}

et cette fois-ci, en toute logique, c’est la vueBonjour  qui s’affiche.
D’ailleurs, nous ne sommes pas limités à ce répertoire. Si nous créons une autre vue à un autre emplacement, disons dans le répertoire /Views/Test/ et que nous l’appelonsEssai , nous pourrons y accéder avec :

public ActionResult Index()
{
    return View("~/Views/Test/Essai.cshtml");
}

On utilise la syntaxe avec le tilde ~ pour indiquer le chemin de la vue, sans oublier son extension car dans ce cas, nous n’utilisons plus directement le mécanisme interne permettant de déterminer la vue.

Afficher les données du modèle

Nous avons vu que nous pouvions facilement afficher des informations dynamiques dans nos vues en les plaçant, depuis le contrôleur, dans le dictionnaireViewData . Il s’agit d’un dictionnaire fourre-tout où nous pouvons mettre des objets en les associant à des clés.
Modifiez votre contrôleur pour avoir :

public ActionResult Index()
{
    ViewData["message"] = "Bonjour depuis le contrôleur";
    ViewData["date"] = DateTime.Now;
    ViewData["resto"] = new Resto { Nom = "Choucroute party", Telephone = "1234" };

    return View();
}

Nous mettons dans ce dictionnaire trois objets différents, une chaîne, une date et unResto , que nous associons à trois clés différentes. Il est ensuite très simple d’exploiter ces données dans la vue :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@ViewData["message"]</li>
    <li>@(((DateTime)ViewData["date"]).ToString("dd/MM/yyyy"))</li>
    <li>@(((ChoixResto.Models.Resto)ViewData["resto"]).Nom)</li>
    <li>@(((ChoixResto.Models.Resto)ViewData["resto"]).Telephone)</li>
</ul>

Et cela nous donne :

Utilisation du dictionnaire ViewData
Utilisation du dictionnaire ViewData

Directement dans le HTML, nous accédons à l’objetViewData  et nous affichons le contenu grâce au caractère @. 

Le caractère spécial @ est interprété par le moteur de vue Razor et permet de mettre du code C# qui sera interprété par le moteur de vue. Ici, on affiche le contenu de la variable. N’importe quel code C# est utilisable. Par exemple, plutôt que de faire deux casts pour accéder au resto, nous aurions pu faire :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@ViewData["message"]</li>
    <li>@(((DateTime)ViewData["date"]).ToString("dd/MM/yyyy"))</li>
    @{
        ChoixResto.Models.Resto resto = (ChoixResto.Models.Resto)ViewData["resto"];
    }
    <li>@resto.Nom</li>
    <li>@resto.Telephone</li>
</ul>

Vous aurez remarqué que nous bénéficions de l’auto-complétion dans la vue. Par exemple, je peux accéder aux propriétés du resto sans problèmes :

Auto-complétion dans la vue
Auto-complétion dans la vue

Il est possible de simplifier l’écriture en utilisant un autre objet pour passer les informations du contrôleur à la vue, qui fonctionne presque pareil que l’objetViewData . Il s’agit de l’objetViewBag  qui est de type dynamic , un des nouveaux types de C# 4.

Par exemple, le code suivant compile sans problèmes :

dynamic resto = new Resto();
resto.Nom = "Resto dynam-hic";
resto.Adresse = "compile, mais ne fonctionnera pas";

mais à l’exécution, lorsque .NET tentera d’accéder à la propriétéAdresse , il va lever une exception car celle-ci n’existe pas.

Vous me direz que ça n’a pas d’intérêt sur cet exemple, ce qui est vrai. En plus, avec un typedynamic , il n’y a pas d’auto-complétion. Bref que des inconvénients… Ici, peut-être, mais regardez comment se transforme le code de notre vue grâce auViewBag  :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@ViewBag.message</li>
    <li>@ViewBag.date.ToString("dd/MM/yyyy")</li>
    <li>@ViewBag.resto.Nom</li>
    <li>@ViewBag.resto.Telephone</li>
</ul>

Plus besoin de cast, ce qui est tout de suite plus clair.

Les vues fortement typées

Quoique… CeViewBag… sans complétion automatique. Ce n’est vraiment pas pratique. Heureusement, il y a encore une autre solution. Plutôt que de passer les données par leViewBag  (ou leViewData ), on peut utiliser le modèle lié à la vue.
Il existe en effet une surcharge de la méthodeView()  qui permet de passer le modèle directement à la vue. Par exemple, imaginons que la vue Index permette d’afficher le détail d’un restaurant, il suffit de passer le restaurant en paramètre de la méthodeView  pour affecter automatiquement notre modèle à ce restaurant :

public class AccueilController : Controller
{
    public ActionResult Index()
    {
        Resto r = new Resto { Nom = "La bonne fourchette", Telephone = "1234" };
        return View(r);
    }
}

Ici, on passe un restaurant tout fraîchement créé en paramètre de la méthodeView . Derrière cela, automatiquement, le moteur du framework affecte la propriétéModel  de la vue à celui qui est passé en paramètre. Cela veut dire que nous pouvons écrire maintenant :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@Model.Nom</li>
    <li>@Model.Telephone</li>
</ul>

Mouais, ce n’est pas trop mal, sauf que par défaut, le modèle de la vue est de typedynamic... donc, y a du mieux mais ce n'est pas encore génial, car il n’y a toujours pas d’auto-complétion sur ce type-là.
Sauf que je connais le type de mon modèle moi ! C’est unResto  ! Et bien, il suffit de le dire à la vue, et ça se passe tout en haut :

@model ChoixResto.Models.Resto

Ici, la syntaxe@model  permet d’indiquer que le modèle de la vue est de typeResto . Et en plus, nous avons maintenant l’auto-complétion qui va bien. Grâce au typage fort de la vue, Visual Studio est capable de savoir que le modèle est de typeResto  :

Typage fort du modèle de la vue
Typage fort du modèle de la vue

Plutôt pratique non ?

Les modèles de vues

OK, ça fonctionne, mais vous avouerez que j’ai un peu triché ici… Au tout début de mon exemple, j’affichais les informations suivantes :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@ViewBag.message</li>
    <li>@ViewBag.date.ToString("dd/MM/yyyy")</li>
    <li>@ViewBag.resto.Nom</li>
    <li>@ViewBag.resto.Telephone</li>
</ul>

Un message, une date et unResto . Et puis là, pour illustrer les vues fortement typées, le message et la date ont disparus comme par enchantement pour me simplifier le travail. :-° Je sens bien que vous avez quand même envie de les afficher !
Je savais bien que mon tour de passe-passe n’allait pas passer inaperçu, mais heureusement j’ai plus d’un tour dans mon sac.

Il suffit de passer les informations complémentaires dans leViewData  (ou leViewBag ). On a donc le modèle dans la propriétéModel  et le reste dans leViewBag . Ce qui donne dans notre contrôleur :

public class AccueilController : Controller
{
    public ActionResult Index()
    {
        ViewData["message"] = "Bonjour depuis le contrôleur";
        ViewData["date"] = DateTime.Now;
        Resto r = new Resto { Nom = "La bonne fourchette", Telephone = "1234" };
        return View(r);
    }
}

Et dans la vue :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@ViewBag.message</li>
    <li>@ViewBag.date.ToString("dd/MM/yyyy")</li>
    <li>@Model.Nom</li>
    <li>@Model.Telephone</li>
</ul>

Voilà… peu pratique mais fonctionnel :p

Non mais oh ! Remboursez ! C’est quoi cette méthode en carton ?

OK OK… En fait, il y a une solution plus élégante, ce que l’on appelle « les modèles de vues », souvent utilisés dans leurs traductions anglaises « view-models ».

Et c’est justement ce qu’on demande ici au view-model, de nous fournir quelque chose de facile et de prêt à l’emploi pour nos vues. En plus, cela nous permet facilement de faire remonter plusieurs éléments du modèle d’un coup. Par exemple la liste de tous les restaurants et de tous les utilisateurs.

Créons alors notre premier view-model. Pour cela, nous allons le mettre dans un répertoire à la racine, nommé ViewModels :

Création du répertoire ViewModels
Création du répertoire ViewModels

Puis créons une classe dedans, que nous appelons par exempleAccueilViewModel  :

public class AccueilViewModel
{
    public string Message { get; set; }
    public DateTime Date { get; set; }
    public Models.Resto Resto { get; set; }
}

Et vous aurez compris qu’il n’y a plus qu’à remplacer le modèle par le view-model dans le contrôleur :

public ActionResult Index()
{
    AccueilViewModel vm = new AccueilViewModel
    {
        Message = "Bonjour depuis le contrôleur",
        Date = DateTime.Now,
        Resto = new Resto { Nom = "La bonne fourchette", Telephone = "1234" }
    };
    return View(vm);
}

Il y a encore une chose à faire : typer correctement la vue avec le view-model. Pour cela, il suffit de modifier la première ligne de la vue :

@model ChoixResto.ViewModels.AccueilViewModel

Et nous aurons cette fois-ci accès à toutes nos propriétés typées, grâce au view-model :

Auto-complétion à partir du view-model
Auto-Complétion à partir du view-model

Le code de la vue n’en est que plus clair :

<div>
    Je suis la vue index
</div>
<ul>
    <li>@Model.Message</li>
    <li>@Model.Date.ToString("dd/MM/yyyy")</li>
    <li>@Model.Resto.Nom</li>
    <li>@Model.Resto.T</li>
</ul>

Et nous avons notre résultat, identique aux précédents, mais tellement mieux :D.

L’inconvénient, car il y en a quand même un, est que nous devons assembler l’objet view-model à partir d’un ou plusieurs éléments du modèle, ce qui reste une tâche peu intéressante, quoiqu’indispensable.

Remarquez que maintenant que nous savons ce qu’est une vue fortement typée, il est possible de se simplifier sa déclaration lorsque nous ajoutons une vue. Il s’agit de choisir le modèle Empty et de choisir une classe de modèle pour créer une vue fortement typée :

Choix d'un modèle pour typer la vue
Choix d'un modèle pour typer la vue

Ici, en choisissant le bon modèle de vue, ainsi que le bon modèle de classe (ici en l’occurrence le view-model), Visual Studio va automatiquement me créer une vue possédant le@model  correctement rempli :

@model ChoixResto.ViewModels.AccueilViewModel

Ce qui nous simplifie encore le travail.

Vous aurez sûrement vu d'autres choix dans la liste déroulante "modèle"… Nous la laissons à empty pour l’instant car nous y reviendrons plus tard, mais sachez que c’est une fonctionnalité qui nous permet de générer des choses dans la vue pour nous simplifier encore le travail. Un peu de patience, nous y reviendrons en fin de cours.

Mixer HTML et C#

Nous avons donc compris que la vue, c’était de l’HTML enrichi. Tout naturellement et tout simplement, nous avons complété notre vue avec des données issues de notre modèle en utilisant le caractère @. Celui-ci nous permet de mettre directement du contenu dynamique dans nos pages.
Pour afficher notre message, nous avons donc pu faire :

<ul>
    <li>@Model.Message</li>
    [...]
</ul>

Nous avons vu que nous pouvions mettre à peu près n’importe quelle expression C# dans le code de la vue, grâce à @. Ceci permet par exemple de faire des affichages conditionnels :

<div>Je suis la vue index</div>
@{
    DayOfWeek jour = Model.Date.DayOfWeek;
    if (jour == DayOfWeek.Saturday || jour == DayOfWeek.Sunday)
    {
        <p>Bon week-end</p>
    }
    else
    {
        <p>Bonne semaine</p>
    }
}

Attention cependant à ne pas trop abuser de cette syntaxe au risque de rapidement voir vos vues devenir illisibles. Ici, il serait peut-être pertinent de « préparer » ce que l’on souhaite afficher grâce à un view-model.

Par contre, utiliser le C# est parfois indispensable. Imaginez par exemple que je souhaite afficher une liste de restaurants dans un tableau HTML. Pour l’exemple, je modifie le view-model pour avoir une liste de restaurants à la place d’un unique restaurant :

public class AccueilViewModel
{
    public string Message { get; set; }
    public DateTime Date { get; set; }
    public List<Models.Resto> ListeDesRestos { get; set; }
}

que j’alimente ainsi dans mon contrôleur :

public ActionResult Index()
{
    AccueilViewModel vm = new AccueilViewModel
    {
        Message = "Bonjour depuis le <span style=\"color:red\">contrôleur</span>",
        Date = DateTime.Now,
        ListeDesRestos = new List<Resto> 
        {
            new Resto { Nom = "Resto pinambour", Telephone = "1234" },
            new Resto { Nom = "Resto tologie", Telephone = "1234" },
            new Resto { Nom = "Resto ride", Telephone = "5678" },
            new Resto { Nom = "Resto toro", Telephone = "555" },
        }
    };
    return View(vm);
}

Grâce à une boucle, voici comment afficher ma liste des restaurants dans une table HTML :

<div>Je suis la vue index</div>
<table>
    <tr>
        <th>Nom</th>
        <th>Téléphone</th>
    </tr>
    @{
        foreach (var resto in Model.ListeDesRestos)
        {
            <tr>
                <td>@resto.Nom</td>
                <td>@resto.Telephone</td>
            </tr>
        }
    }
</table>

Et nous avons :

Affichage via une boucle dans la vue
Affichage via une boucle dans la vue

J'ai bien sûr ajouté un peu de CSS pour avoir quelques bordures :

<style type="text/css">
    table {
        border-collapse: collapse;
    }

    td, th {
        border: 1px solid black;
    }
</style>

Mais c’est accessoire :p.

Voilà pour ce tableau, plutôt simple non ? Tout ça grâce à notre boucleforeach  et à la capacité d’ASP.NET MVC à mixer simplement le HTML et le code C#.

Et pour les contrôles de formulaires ? C’est pareil. On mixe ! Comme David G. !

Revenons à notre ancien view-model où nous avons un unique restaurant et pas une liste. Nous pouvons donc simplement faire une page avec des contrôles de formulaire :

<div>Je suis la vue index</div>
<input type="text" id="nom" value="@Model.Resto.Nom" />
<input type="text" id="telephone" value="@Model.Resto.Telephone" />
<input type="submit" value="Envoyer" />

Et le HTML est sans surprises :

Affichage du formulaire pré-rempli
Affichage du formulaire pré-rempli

Grâce à l’attribut value correctement rempli, les zones de texte sont pré-remplies. Parfait.

Bon, je pense que vous avez saisi le principe général, alors je ne vais pas vous faire tous les contrôles HTML de la planète :p.

Example of certificate of achievement
Example of certificate of achievement