Как создать вложенные ViewComponents в Monorail и NVelocity?
Меня попросили обновить меню на веб-сайте, который мы поддерживаем. Сайт использует Castle Windors Monorail и NVelocity в качестве шаблона. В настоящее время меню отображается с использованием пользовательских подклассов ViewComponent, которые отображают элементы li. На данный момент существует только один (горизонтальный) уровень, поэтому с текущим механизмом все в порядке.
Меня попросили добавить выпадающие меню в некоторые из существующих меню. Поскольку я впервые вижу Монорельс и NVelocity, я немного растерялся.
Что в настоящее время существует:
<ul>
#component(MenuComponent with "title=Home" "hover=autoselect" "link=/")
#component(MenuComponent with "title=Videos" "hover=autoselect")
#component(MenuComponent with "title=VPS" "hover=autoselect" "link=/vps")
#component(MenuComponent with "title=Add-Ons" "hover=autoselect" "link=/addons")
#component(MenuComponent with "title=Hosting" "hover=autoselect" "link=/hosting")
#component(MenuComponent with "title=Support" "hover=autoselect" "link=/support")
#component(MenuComponent with "title=News" "hover=autoselect" "link=/news")
#component(MenuComponent with "title=Contact Us" "hover=autoselect" "link=/contact-us")
</ul>
Возможно ли иметь вложенные MenuComponents (или новый SubMenuComponent) что-то вроде:
<ul>
#component(MenuComponent with "title=Home" "hover=autoselect" "link=/")
#component(MenuComponent with "title=Videos" "hover=autoselect")
#blockcomponent(MenuComponent with "title=VPS" "hover=autoselect" "link=/vps")
#component(SubMenuComponent with "title="Plans" "hover=autoselect" "link=/vps/plans")
#component(SubMenuComponent with "title="Operating Systems" "hover=autoselect" "link=/vps/os")
#component(SubMenuComponent with "title="Supported Applications" "hover=autoselect" "link=/vps/apps")
#end
#component(MenuComponent with "title=Add-Ons" "hover=autoselect" "link=/addons")
#component(MenuComponent with "title=Hosting" "hover=autoselect" "link=/hosting")
#component(MenuComponent with "title=Support" "hover=autoselect" "link=/support")
#component(MenuComponent with "title=News" "hover=autoselect" "link=/news")
#component(MenuComponent with "title=Contact Us" "hover=autoselect" "link=/contact-us")
</ul>
Мне нужно нарисовать подменю (элементы ul и li) внутри переопределенного метода Render на MenuComponent, поэтому использование вложенных производных ViewComponent может не работать. Я хотел бы, чтобы метод оставался в основном декларативным методом для создания меню, если это вообще возможно.
редактировать: я могу использовать Context.RenderBody() для рендеринга вложенных производных ViewComponent, но они отображаются перед родителем. Я предполагаю, что разметка подменю должна каким-то образом подключаться к тому же выводу, что и родительский?
2 ответа
Мой оригинальный метод рендеринга выглядел как
public override void Render()
{
var buffer = new StringBuilder();
var extraClass = _hoverState == MenuHoverState.Selected ? "class=\"Selected\"" : "";
// Menu Item Start
buffer.Append("<li><a href=\"" + ComponentParams["link"] + "\"" + extraClass + ">");
// Menu Text
buffer.Append(ComponentParams["title"]);
// Menu Item End
buffer.Append("</a></li>");
RenderText(buffer.ToString());
}
Мне нужно было подключиться к Context.Writer:
public override void Render()
{
var buffer = new StringBuilder();
var extraClass = _hoverState == MenuHoverState.Selected ? "class=\"Selected\"" : "";
// Menu Item Start
buffer.Append("<li><a href=\"" + ComponentParams["link"] + "\"" + extraClass + ">");
// Menu Text
buffer.Append(ComponentParams["title"]);
// Menu Item End
buffer.Append("</a><ul class=\"subMenu\" style=\"display:none;\">");
Context.Writer(buffer.ToString());
Context.RenderBody(Context.Writer);
Contet.Writer("</ul></li>");
}
Я могу использовать Context.RenderBody() для рендеринга вложенных производных ViewComponent
в переопределении метода Render вы можете использовать что-то вроде
RenderView("header");
RenderBody();
RenderView("footer");
и, возможно, использовать RenderSection может быть полезно, чтобы иметь возможность переопределить некоторые части из шаблона, который вы используете компонент
if(HasSection("header")){
RenderSection("header");
} else {
RenderView("header");
}
Также возможно изменить и изменить контекст:
for(var item in this.SubItems){
PropertyBag["item"] = item;
if(HasSection("item")){
RenderSection("item");
} else {
RenderView("item");
}
}
все эти решения причудливы, но я, как правило, предпочитаю иметь видовой компонент, который принимает целевую модель представления (скажем, HierarchicalMenuViewModel) в качестве параметра и сохраняет логику шаблонов простой, ее проще использовать, и происходит выходная настройка
по крайней мере, для простых элементов управления (которые когда-нибудь заслуживают только макрос или частичное в зависимости от viewengine).
В конце концов, представленные выше концепции viewcomponent все еще хороши, когда вы выполняете управление, которое требует дополнительной настройки. Совет должен позаботиться о документировании логики рендеринга или о ее простоте (<= 10 строк в методе рендеринга)