Utiliser le panel de Bootrap n’est pas forcément ce qu’il y a de plus trivial. Surtout, s’il faut le reproduire à plusieurs reprises dans une même page :

<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title">My title</h3>
    </div>
    <div class="panel-body">
    ...
    </div>
</div>

En .net MVC, heureusement il est possible d’écrire des Helpers pour cela. Certain auront peut-être la tentation de créer deux méthode façon script PHP :

@Html.BeginPanel("My title")
…
@Html.EndPanel()

Heureusement, un Helper peut être incrusté dans un block using. Ce qui rend son usage plus trivial :

@using(Html.BeginPanel("My title"))
{
    …
}

Pour arriver à cela, on ne doit maitriser quelques concepts simples :

  • Le block using a besoin d’une instance d’une classe implémentant l’interface IDisposable
  • Le constructeur de cette classe va écrire le début du code HTML utile.
  • La méthode Dispose de cette classe doit écrire les balises HTML fermantes utiles.
  • Pour écrire directement sur la vue MVC, il faut utiliser la méthode Write du contexte de la vue : htmlHelper.ViewContext.Writer.Write("…").

La première étape consiste donc à créer une classe disposable :

  • L’appel du constructeur va écrire le début du panel Bootstrap.
  • L’instance appelante de HtmlHelper est conservée pour permettre son usage dans le Dispose.
  • L’appel du Dispose va écrire les deux balises fermantes des Div ouvertes dans le constructeur.
/// <summary>
/// Panel bootstrap pouvant être utilisé dans un block using d'un vue MVC
/// </summary>
public sealed class MvcPanel : IDisposable
{
    private readonly HtmlHelper _htmlHelper;

    /// <summary>
    /// Constructeur
    /// </summary>
    /// <param name="htmlHelper"></param>
    /// <param name="title">Titre du panel</param>
    public MvcPanel(HtmlHelper htmlHelper, string title)
    {
        _htmlHelper = htmlHelper;

        // Création du container
        var container = new TagBuilder("div");
        container.AddCssClass("panel");
        container.AddCssClass("panel-default");

        // Création du container du header
        var headerContainer = new TagBuilder("div");
        headerContainer.AddCssClass("panel-heading");

        // Création du header
        var header = new TagBuilder("h3");
        header.AddCssClass("panel-title");
        header.InnerHtml = title;

        // Ajout du header à son container
        headerContainer.InnerHtml = header.ToString();

        // Création du container du body
        var bodyContainer = new TagBuilder("div");
        bodyContainer.AddCssClass("panel-body");

        _htmlHelper.ViewContext.Writer.Write(
            String.Concat(
                container.ToString(TagRenderMode.StartTag),
                headerContainer.ToString(),
                bodyContainer.ToString(TagRenderMode.StartTag)));
    }

    /// <summary>
    /// Dispose, met fin au block
    /// </summary>
    public void Dispose()
    {
        _htmlHelper.ViewContext.Writer.Write("</div></div>");
    }
}

Après cela, l’écriture du Helper est triviale. Celui-ci a uniquement pour vocation de retourner une instance de la classe MvcPanel :

public static class PanelExtensions
{
    /// <summary>
    /// Création d'une Panel bootstrap à utiliser dans un block using
    /// </summary>
    /// <param name="htmlHelper">Helper</param>
    /// <param name="title">titre affiché sur le panel</param>
    /// <returns></returns>
    public static MvcPanel BeginPanel(this HtmlHelper htmlHelper, string title)
    {
        return new Html.MvcPanel(htmlHelper, title);
    }
}

Simple et trivial ;)