如何在 Monorail 和 NVelocity 中创建嵌套 ViewComponent?

发布于 2024-08-31 07:13:21 字数 2441 浏览 6 评论 0原文

我被要求更新我们维护的网站上的菜单。该网站使用 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>

我需要在 MenuComponent 上重写的 Render 方法内绘制子菜单(ul 和 li 元素),因此使用嵌套的 ViewComponent 衍生物可能不起作用。如果可能的话,我希望有一种方法保留创建菜单的基本声明性方法。

编辑:我可以使用 Context.RenderBody() 渲染嵌套的 ViewComponent 衍生物,但它们是在父级之前渲染的。我猜子菜单的渲染需要以某种方式连接到与父菜单相同的输出?

I have been asked to update the menu on a website we maintain. The website uses Castle Windors Monorail and NVelocity as the template. The menu is currently rendered using custom made subclasses of ViewComponent, which render li elements. At the moment there is only one (horizontal) level, so the current mechanism is fine.

I have been asked to add drop down menus to some of the existing menus. As this is the first time I have seen Monorail and NVelocity, I'm a little lost.

What currently exists:

<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>

Is it possible to have nested MenuComponents (or a new SubMenuComponent) something like:

<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>

I need to draw the sub menu (ul and li elements) inside the overridden Render method on MenuComponent, so using nested ViewComponent derivatives may not work. I would like a method keep the basically declarative method for creating menus, if at all possible.

edit: I can use Context.RenderBody() to render the nested ViewComponent derivitives, but they're being rendered before the parent. I guess the rending of the sub menus need to somehow hook into the same output as the parent?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心作怪 2024-09-07 07:13:22

我原来的渲染方法看起来像

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>");    
}

My original render method looked like

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());
}

I needed to hook into the 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>");    
}
梦在深巷 2024-09-07 07:13:22

我可以使用 Context.RenderBody() 渲染嵌套的 ViewComponent 派生

我可以使用 Context.RenderBody()在 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 行)

I can use Context.RenderBody() to render the nested ViewComponent derivitives

in your Render method override, you could use something like

RenderView("header");
RenderBody();
RenderView("footer");

and maybe use RenderSection could be useful to be able to override some parts from the template you use the component

if(HasSection("header")){
    RenderSection("header");
} else {
    RenderView("header");
}

it is also possible to itterate and alter the context:

for(var item in this.SubItems){
    PropertyBag["item"] = item;
    if(HasSection("item")){
        RenderSection("item");
    } else {
        RenderView("item");
    }
}

all these solution are fancy, but I generaly prefer having a viewcomponent which takes a purpose specific viewmodel (say HierarchicalMenuViewModel) as a parameter and keep the templating logic simple, it's more easy to use, and output customization happen

at least for simple controls (that would sometime only deserve a macro or partial depending on the viewengine).

In the end, viewcomponent concepts illustrated above are still nice to have when doing control that need more customization. An advice is to take care of documenting the rendering logic or keeping it simple (<= 10 lines in render method)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文