Adaptation d'un Helper personnalisé Html pour rasoir (il utilise HtmlTextWriter donc retourne void)

StackOverflow https://stackoverflow.com/questions/4217611

  •  26-09-2019
  •  | 
  •  

Question

Le problème

J'ai un menu très astucieux Html aide écrite pour les vues de WebFormViewEngine. Ce moteur permet à vos aides de revenir vide, et toujours être en mesure d'utiliser:

@Html.Theseus

Il est parfait pour mon aide, car il peut alors rendre le menu à l'aide HtmlTextWriter, qui rend directement au flux de sortie.

Dans les vues Razor, cependant, les aides Html devraient retourner une valeur (généralement MvcHtmlString) qui est ce qui est ajouté à la sortie. Petite différence, grande conséquence.

Il y a un moyen de contourner cela, comme en pointe par me GvS (voir ASP.NET MVC 2 à MVC 3: custom Html helpers Razor) comme suit:

Si le retour d'aide vide, puis procédez comme suit:

@{Html.Theseus;}

(Essentiellement, vous êtes juste d'appeler la méthode, plutôt que de rendre dans la vue).

Alors qu'il était encore soigné, ce n'est pas tout à fait la même chose que @ Html.Theseus. Alors ...

Mon code est complexe, mais fonctionne très bien, donc il répugne à passer par des modifications majeures, à savoir, en remplaçant le HtmlTextWriter avec un autre écrivain. Un extrait du code va comme:

writer.AddAttribute(HtmlTextWriterAttribute.Href, n.Url);
writer.AddAttribute(HtmlTextWriterAttribute.Title, n.Description);
writer.RenderBeginTag(HtmlTextWriterTag.A);
writer.WriteEncodedText(n.Title);
writer.RenderEndTag();

// Recursion, if any
// Snip off the recursion at this level if specified by depth
// Use a negative value for depth if you want to render the entire sitemap from the starting node

    if ((currentDepth < depth) || (depth < 0))
    {
         if (hasChildNodes)
         {
              // Recursive building starts here

              // Open new ul tag for the child nodes 
              // "<ul class='ChildNodesContainer {0} Level{1}'>"; 
              writer.AddAttribute(HtmlTextWriterAttribute.Class, "Level" + currentDepth.ToString());
              writer.RenderBeginTag(HtmlTextWriterTag.Ul);

              // BuildMenuLevel calls itself here to 
              // recursively traverse the sitemap hierarchy, 
              // building the menu as I go.
              // Note: this is where I increase the currentDepth variable!
               BuildChildMenu(currentDepth + 1, depth, n, writer);

              // Close ul tag for the child nodes
              writer.RenderEndTag();
          }
    }

Il ne serait pas amusant de re écrire avec TagBuilders. En l'état actuel, il rend tout type de menu, y compris la « incrémental de navigation », comme décrit dans mon article 4guysfromrolla: mise en œuvre progressive Navigation avec ASP.NET

Les options:

Je suppose que je pourrais retourner un MvcHtmlString vide, mais qui est à peu près la définition d'un hack ...

La seule alternative est à la tête vers le soleil couchant et de réécrire l'aide en utilisant la TagBuilder pour construire chaque balise, l'ajouter à un StringBuilder, puis construire la balise suivante, etc, puis utilisez l'instance de StringBuilder pour créer le MvcHtmlString. Sérieusement laid, à moins que je pouvais faire quelque chose comme ...

La question:

Est-il possible à:

Arrêter le rendu HtmlTextWriter au flux et au lieu de l'utiliser comme un StringBuilder à la fin du processus que j'utilise pour créer un MvcHtmlString (ou HtmlString)?

Ça a l'air peu probable, comme je vous écris ...

PS:

La grande chose au sujet de la HtmlTextWriter est que vous pouvez construire de grandes quantités d'étiquettes, au lieu de les construire un par un comme un TagBuilder.

Était-ce utile?

La solution

Contrairement aux réponses que vous avez reçu pour votre autre question Razor ne nécessite pas que vous retournez un HtmlString. Le problème avec votre code est en ce moment que vous écrivez directement pour le flux de réponse. Razor exécute les choses à l'envers ce qui signifie que vous pouvez gâcher l'ordre de réponse (voir un question similaire ).

Dans votre cas, vous pouvez probablement le faire (bien que je ne l'ai pas testé):

public static void Theseus(this HtmlHelper html)
{
    var writer = new HtmlTextWriter(html.ViewContext.Writer);
    ...
}

Modifier (suivi pour répondre à vos commentaires):

Html Helpers sont parfaitement capables de retourner soit un HtmlString directement ou non avenue et écrit à l'auteur de contexte. Par exemple, les travaux Html.Partial et Html.RenderPartial bien dans Razor. Je pense que vous confondez est le syntaxe requis pour appeler une version et pas l'autre.

Par exemple, considérons une vue Aspx:

<%: Html.Partial("Name") %>
<% Html.RenderPartial("Name") %>

Vous appelez chaque méthode différemment. Si vous feuilletez les choses, les choses vont tout simplement pas. De même, dans Razor:

@Html.Partial("Name")
@{ Html.RenderPartial("Name"); }

Maintenant, il se trouve que la syntaxe à utiliser un assistant vide est beaucoup plus bavard dans Razor par rapport à Aspx. Cependant, les deux fonctionnent très bien. À moins que vous vouliez dire quelque chose d'autre par « la question est d'une aide HTML ne pas être en mesure de revenir vide ».

Par ailleurs, si vous voulez vraiment appeler votre aide en utilisant cette syntaxe: @Html.Theseus() vous pouvez faire ceci:

public static IHtmlString Theseus(this HtmlHelper html)
{
    var writer = new HtmlTextWriter(html.ViewContext.Writer);
    ...
    return new HtmlString("");
}

Mais qui est un peu un hack.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top