Как создать вложенные ViewComponents в Monorail и NVelocity?

Меня попросили обновить меню на поддерживаемом нами веб-сайте. Веб-сайт использует в качестве шаблона Castle Windors Monorail и NVelocity. В настоящее время меню отображается с использованием настраиваемых подклассов ViewComponent, которые отображают элементы li. На данный момент есть только один (горизонтальный) уровень, так что текущий механизм в порядке.

Меня попросили добавить раскрывающиеся меню к некоторым из существующих меню. Поскольку я впервые вижу Monorail и 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>

Возможно ли иметь вложенные компоненты меню (или новый компонент подменю), например:

<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 может не работать. Я хотел бы, чтобы метод сохранял в основном декларативный метод создания меню, если это вообще возможно.

edit: я могу использовать Context.RenderBody () для рендеринга вложенных производных ViewComponent, но они отображаются раньше родителя. Я предполагаю, что отображение подменю должно каким-то образом подключаться к тому же выходу, что и родительский?


person Rob Gray    schedule 05.05.2010    source источник


Ответы (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>");    
}
person Rob Gray    schedule 05.05.2010

Я могу использовать 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) и сохраняет простую логику шаблонов, ее проще использовать, и происходит настройка вывода

по крайней мере, для простых элементов управления (которые когда-нибудь заслуживают только макроса или части, в зависимости от движка просмотра).

В конце концов, концепции компонентов представления, проиллюстрированные выше, по-прежнему полезно иметь при выполнении управления, требующего дополнительной настройки. Совет - позаботьтесь о документировании логики рендеринга или сохранении простоты (‹= 10 строк в методе рендеринга)

person smoothdeveloper    schedule 21.06.2010