2012-08-01 98 views
5

我有一个块级元素,一个容器,当隐藏它的子Wicket元素(按钮)时,应该隐藏它的所有全部。换句话说,如果任何子按钮是可见的,容器应该是可见的。在隐藏其所有子组件时隐藏的Wicket容器

如果有按钮的话,前面的按钮总是可见的,所以我使用该按钮来控制<wicket:enclosure>的可见性,纯粹在HTML端处理所有这些。

现在,规格已经改变,因此按钮可以独立隐藏/可见,所以简单的外壳将不再工作(我认为)。

我得到了它这样的工作:

HTML:

<wicket:container wicket:id="downloadButtons"> 
    <wicket:message key="download.foo.bar"/>: 
    <input type="button" wicket:id="excelDownloadButton" wicket:message="value:download.excel"/> 
    <input type="button" wicket:id="textDownloadButton" wicket:message="value:download.text"/> 
    <!-- etc ... --> 
</wicket:container> 

的Java:

WebMarkupContainer container = new WebMarkupContainer("downloadButtons"); 

// ... add buttons to container ... 

boolean showContainer = false; 
Iterator<? extends Component> it = container.iterator(); 
while (it.hasNext()) { 
    if (it.next().isVisible()) { 
     showContainer = true; 
     break; 
    } 
} 
addOrReplace(container.setVisible(showContainer)); 

但Java端现在是那种冗长和丑陋,我是思考有可能是一个更干净的方式来做同样的事情。在那儿?你可以以某种方式“自动”隐藏一个容器(及其所有额外的标记),当它的子组件都不可见时?

(检票1.4,如果它很重要。)

回答

10

时,如果你想这是可重复使用的,如果ISVISIBLE()返回true,则可以将其定义为对连接至任何容器一个IComponentConfigurationBehavior(对于检票版本> 1.4.16),然后设置在onConfigure()方法行为的容器的可见性:

class AutoHidingBehavior extends AbstractBehavior { 

    @Override 
    public void bind(Component component) { 
     if (! (component instanceof MarkupContainer)) { 
      throw new IllegalArgumentException("This behavior can only be used with markup containers"); 
     } 
    } 

    @Override 
    public void onConfigure(Component component) { 
     MarkupContainer container = (MarkupContainer) component; 
     boolean hasVisibleChildren = false; 
     for (Iterator<? extends Component> iter = container.iterator(); iter.hasNext();) { 
      if (iter.next().isVisible()) { 
       hasVisibleChildren = true; 
       break; 
      } 
     } 
     container.setVisible(hasVisibleChildren); 
    } 

} 
+0

不错;这种方法对我来说是新的,现在我已经在我们的代码中实现了它,它也非常优雅。 (原始页面大大简化,这可以促进重用。) – Jonik 2012-08-01 11:02:45

4

您可以覆盖容器的isVisible方法返回true,如果任何一个孩子的是可见的(评估孩子的知名度就像你现在做的)。这不会大幅减少代码,但在我眼中它会更好,因为确定可见性的代码就是它所属的“代码”。你可以使这个专门的容器类来进一步封装代码。

或者您可以子类EnclosureContainer并添加您需要的任何可见性逻辑。

注:当重写ISVISIBLE ...

[...]警告说,这有几个缺陷:

  • 它被称为每个请求多次,可能几十次,所以保持实现计算光

  • 这个值应该保持整个渲染/响应边界的稳定。这意味着渲染一个按钮, 但按钮被点击返回false时,你会得到一个错误

Wicket in Action

+0

谢谢。关于EnclosureContainer:你可以使用它,但是据我的理解,它没有任何好处。 WebMarkupContainer在这里。如我错了请纠正我。 (它希望*一个*子组件来控制可见性 - 如果我只有一个,它确实会有用。) – Jonik 2012-08-01 09:02:59

+0

我主要在寻找一种避免有点丑陋的迭代代码来确定容器可见性的方法 - 我在那里有一个预感会有某种方式。但是,当然,如果代码尽可能干净,那也是一个有效的答案... – Jonik 2012-08-01 09:05:31

+0

+1:但是最好将WebMarkupContainer子类化并在其中添加可见性检查。正是因为这个原因,我上周才写了这样的一堂课。 – 2012-08-01 09:54:10

0

您也可以使用访问者。

在我的情况下,我有容器与面板中的链接。代码:

public abstract class MyPanel extends Panel 
{ 
    private final WebMarkupContainer webMarkupContainer; 

    public MyPanel(String id) 
    { 
     super(id); 

     webMarkupContainer = new WebMarkupContainer("customContainer") 
     { 
     @Override 
     protected void onBeforeRender() 
     { 
      super.onBeforeRender(); 
      boolean visible = Boolean.TRUE.equals(checkVisibleLinks()); 
      setVisible(visible); 
     } 
     }; 

     AjaxLink myLink = new AjaxLink("myLink") 
     { 
     @Override 
     public void onClick(AjaxRequestTarget target) 
     { 
      //some action 
     } 

     }; 

     webMarkupContainer.add(myLink); 
    } 

    private Boolean checkVisibleLinks() 
    { 
     return webMarkupContainer.visitChildren(AbstractLink.class, new IVisitor<AbstractLink, Boolean>() 
     { 
     @Override 
     public void component(AbstractLink link, IVisit<Boolean> visit) 
     { 
      if (link.isVisible()) 
      { 
       visit.dontGoDeeper(); 
       visit.stop(true); 
      } 
     } 
     }); 
    } 

}