Проблема
У меня очень изящный помощник по Html меню, написанный для представлений WebFormViewEngine. Этот механизм позволяет вашим помощникам возвращать пустоту и при этом использовать:
@Html.Theseus
Это отлично подходит для моего помощника, потому что он может затем визуализировать меню, используя HtmlTextWriter, который визуализирует непосредственно в выходной поток.
Однако в представлениях Razor помощники Html должны возвращать значение (обычно MvcHtmlString), которое и добавляется в вывод. Маленькая разница, большое следствие.
Существует способ обойти это, как указал мне GvS (см. ASP.NET MVC 2 - MVC 3: пользовательские помощники HTML в Razor ) следующим образом:
Если помощник возвращает void, выполните следующие действия:
@{Html.Theseus;}
(По сути, вы просто вызываете метод, а не выполняете рендеринг в представление).
Хотя все еще аккуратно, это не совсем то же самое, что @ Html.Theseus. Итак ...
Мой код сложен, но работает очень хорошо, поэтому мне не терпится пройти через основные изменения, т. Е. Заменить HtmlTextWriter другим писателем. Фрагмент кода выглядит так:
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();
}
}
Не было бы весело переписать с TagBuilders. В его нынешнем виде он отображает меню любого типа, включая «Инкрементную навигацию», как описано в моей статье 4guysfromrolla:
Реализация пошаговой навигации с ASP.NET
Опции:
Полагаю, я мог бы вернуть пустую строку MvcHtmlString, но это в значительной степени определение хака ...
Единственная альтернатива - отправиться на закат и переписать помощника, используя TagBuilder для создания каждого тега, добавить его в StringBuilder, затем создать следующий тег и т. Д., А затем использовать экземпляр StringBuilder для создания MvcHtmlString. Серьезно уродливо, если я не смогу сделать что-то вроде ...
Вопрос:
Есть ли способ:
Остановить рендеринг HtmlTextWriter в поток и вместо этого использовать его как StringBuilder, который в конце процесса я использую для создания MvcHtmlString (или HtmlString)?
Звучит невероятно, даже когда я пишу ...
PS:
Самое замечательное в HtmlTextWriter заключается в том, что вы можете создавать большое количество тегов, а не создавать их один за другим, как в TagBuilder.