wicket : Unable to find component with id ... with table , listview and populateitem - wicket

Excuse me, i'm newest in wicket and i have an error that i can't fix. please help me !
here a consultation page:
<body>
<wicket:extend>
<div>
<a href="#" wicket:id="idLinkHaut"><img wicket:id="imgRetourHaut" /><span>
Retour</span></a>
</div>
<div class="marginTop">
<span wicket:id="panelDiagnosticEquipementsReseauxLocal" />
</div>
<div class="marginTop">
<img wicket:id="imgRetourBas" /><span>Retour</span>
</div>
</wicket:extend>
</body>
the java page : consultation.java
public class ConsultationPage extends HeaderTemplatePage {
#SpringBean(name = "dao")
private GetDiagnosticDao dao;
/**
* Constructeur de la page de consultation
*
* #param pp
* les paramètres de la page
*/
public ConsultationPage(PageParameters pp) {
super(pp);
String idDiagnostic = ConstantesGlobales.PARAMETRE_ID_DIAGNOSTIC);
// utile pour les liens RETOUR
String singleResult =ConstantesGlobales.PARAMETRE_SINGLE_RESULT;
// ndClient saisi dans le formulaire
String numeroClient = ConstantesGlobales.PARAMETRE_ND_CLIENT_DEMANDE;
// nunmerolient saisi dans le formulaire
String typeDiag = ConstantesGlobales.PARAMETRE_TYPE_DIAGNOSTIC;
Diagnostic diagnostic = null;
String codeErreurException = StringUtils.EMPTY;
if (StringUtils.isNotBlank(idDiagnostic)) {
try {
diagnostic = dao.getDiagnostic(idDiagnostic);
numeroClient = getNdClient(nunmerolient, diagnostic);
LOGGER.debug("Détail du diagnostic " + idDiagnostic + " pour le client " + numeroClient);
} catch (FunctionalException | TechnicalException e) {
codeErreurException = e.getMessage();
}
}
// HomePage
if (StringUtils.isNotEmpty(codeErreurException)) {
PageParameters consultationPageParameters = new PageParameters();
consultationPageParameters.set(ConstantesGlobales.PARAMETRE_CODE_ERREUR, codeErreurException);
consultationPageParameters.set(ConstantesGlobales.PARAMETRE_CLIENT, numeroClient);
consultationPageParameters.set(ConstantesGlobales.PARAMETRE_TYPE_DIAGNOSTIC, typeDiag);
throw new RestartResponseException(ListeDiagnosticsPage.class, consultationPageParameters);
} else {
// Titre de la page du navigateur
add(new Label("titrePage", nunmerolient + " : diagnostic détaillé"));
PageParameters pars = new PageParameters();
if (WicketSession.get().isAppelPATH()) {
pars.add(ConstantesGlobales.PARAMETRE_ORIGINE, ConstantesGlobales.VALEUR_ORIGINE_PATH);
}
if (!StringUtils.equals(ConstantesGlobales.VALEUR_SINGLE_RESULT, singleResult)) {
// cas plusieurs diagnostics pour le numeroClient
pars.add(ConstantesGlobales.PARAMETRE_CLIENT, numeroClient);
pars.add(ConstantesGlobales.PARAMETRE_TYPE_DIAGNOSTIC, typeDiag);
}
ajouterLienHaut(pars);
ajouterLienBas(pars);
final ListeEquipementReseauLocal listeEquipements = new ListeEquipementReseauLocal("panelDiagnosticEquipementsReseauxLocal", diagnostic);
add(listeEquipements);
}
}
/**
* #param pars
*/
private void ajouterLienBas(PageParameters pars) {
final BookmarkablePageLink<ListeDiagnosticsPage> linkBas = new BookmarkablePageLink<>("idLinkBas",
ListeDiagnosticsPage.class, pars);
linkBas.add(new Image("imgRetourBas", new PackageResourceReference(LocateResources.class, GIF)));
add(linkBas);
}
/**
* #param pars
*/
private void ajouterLienHaut(PageParameters pars) {
final BookmarkablePageLink<ListeDiagnosticsPage> linkHaut = new BookmarkablePageLink<>("idLinkHaut",
ListeDiagnosticsPage.class, pars);
linkHaut.add(new Image("imgRetourHaut", new PackageResourceReference(LocateResources.class, GIF)));
add(linkHaut);
}
/**
* Cette méthode permet de récupérer le numeroClient dans le cas mode
* d'accÚs depuis la fenêtre e-chat
*
* #param numeroClient
* #param diagnostic
* #return
*/
private String getNunmerolient(String numeroClient, Diagnostic diagnostic) {
if (StringUtils.isEmpty(numeroClient) && diagnostic.getDiagnostic() != null) {
final MonDiagnostic monDiagnostic = diagnostic.getDiagnostic();
if (monDiagnostic.getInstalledOffer() != null && monDiagnostic.getInstalledOffer().getAliases() != null) {
final Alias alias = monDiagnostic.getInstalledOffer().getAliases();
if (StringUtils.isNotBlank(alias.getNd())) {
numeroClient = alias.getNd();
}
}
}
return numeroClient;
}
}
the panelDiagnosticEquipementsReseauxLocal has been built by:
listEquipementReseau.html
<html xmlns:wicket="http://wicket.apache.org/">
<wicket:panel>
<div class="Block">
<p class="titreTableau">Diagnostic des équipements du réseau local</p>
<table class="tableauData" cellspacing="0">
<tbody>
<tr class="titreCentre">
<th>Nom de l'équipement</th>
<th>Adresse MAC</th>
<th>Diagnostic</th>
</tr>
<tr class="liste" wicket: id="listeEquipements">
<td><span wicket:id="idNomEquipement"></span></td>
<td><span wicket:id="idMAC"></span></td>
<td><span wicket:id="idDiagnostic"></span></td>
</tr>
</tbody>
</table>
</div>
</wicket:panel>
</html>
And by ListeEquipementReseauLocal.java
public class ListeEquipementReseauLocal extends Panel {
/**
*
*/
private static final long serialVersionUID = -3844512423568512666L;
private final String LBOX = "LB_MAC";
public ListeEquipementReseauLocal(String id, Diagnostic diagnostic) {
super(id);
// TODO Auto-generated constructor stub
if (diagnostic == null) {
this.setVisible(false);
} else {
final List<EquipementReseauLocal> listeEquipements = getDataEquipements(diagnostic);
final DataviewListeEquipementsReseauLocal dataView = new DataviewListeEquipementsReseauLocal("listeEquipements",
new ListDataProvider<EquipementReseauLocal>(listeEquipements));
add(dataView);
}
}
/**
* Cette méthode permet de récupérer les données pour le bloc Tests Réalisés
*
* #param diagnostic
* #return
*/
public List<EquipementReseauLocal> getDataEquipements(final Diagnostic diagnostic) {
final List<EquipementReseauLocal> listeEquipements = new ArrayList<EquipementReseauLocal>();
if (diagnostic.getDiagnostic() != null && CollectionUtils.isNotEmpty(diagnostic.getDiagnostic().getLanActions())) {
for (Action action : diagnostic.getDiagnostic().getLanActions()) {
final EquipementReseauLocal equipement = new EquipementReseauLocal();
if (action.getServiceTest() != null) {
final ServiceTest serviceTest = action.getServiceTest();
if (serviceTest.getResultSummary() != null) {
final ResultSummary resultSummary = serviceTest.getResultSummary();
final List<ResultDetails> listResultDetails= serviceTest.getResultDetails();
// Code Diagnostic
if (StringUtils.isNotBlank(resultSummary.getEvaluationCode())) {
equipement.setDiagnostic(resultSummary.getCodeDiagnostic());
}
for(ResultDetails rd : listResultDetails) {
// Libellé équipement
if (StringUtils.isNotBlank(rd.getKey()) && !(rd.getKey().equalsIgnoreCase("DATE"))) {
if(rd.getKey().equalsIgnoreCase(LBOX))
equipement.setNomEquipement("Livebox");
if(rd.getKey().equalsIgnoreCase(LBOX))
equipement.setNomEquipement("Galaxy-S8-1");
if(rd.getKey().equalsIgnoreCase(LBOX))
equipement.setNomEquipement("Mini-nous");
if(rd.getKey().equalsIgnoreCase(LBOX))
equipement.setNomEquipement("Decodeur TV");
// MAC
if (StringUtils.isNotBlank(rd.getValue())) {
equipement.setAdresseMac(rd.getValue());
}
}
}
}
}
listeEquipements.add(equipement);
}
}
return listeEquipements;
}
}
the table is filling by
DataviewListeEquipementsReseauLocal.java
public class DataviewListeEquipementsReseauLocal extends DataView<EquipementReseauLocal> {
private static final long serialVersionUID = 3176152958105694572L;
private static final Logger LOGGER = Logger
.getLogger(DataviewListeEquipementsReseauLocal.class);
/**
* Constructeur
*
* #param id
* #param dataProvider
*/
public DataviewListeEquipementsReseauLocal(final String id,
final IDataProvider<EquipementReseauLocal> dataProvider) {
super(id, dataProvider);
}
#Override
protected void populateItem(Item<EquipementReseauLocal> item) {
final EquipementReseauLocal equipement = item.getModelObject();
String nomEquipement = ConstantesGlobales.NO_BREAK_SPACE;
String adresseMAC = ConstantesGlobales.NO_BREAK_SPACE;
String diagnostic = ConstantesGlobales.NO_BREAK_SPACE;
if (equipement != null) {
if (StringUtils.isNotEmpty(equipement.getNomEquipement())) {
nomEquipement = equipement.getNomEquipement();
}
if (StringUtils.isNotEmpty(equipement.getAdresseMac())) {
adresseMAC = equipement.getAdresseMac();
}
if (StringUtils.isNotEmpty(equipement.getDiagnostic())) {
diagnostic = equipement.getDiagnostic();
}
}
item.add(new CustomLabel("idNomEquipement", nomEquipement));
item.add(new CustomLabel("idMAC", adresseMAC));
item.add(new CustomLabel("idDiagnostic", diagnostic));
}
}
When i execute this code, this application, i have this error:
2018-12-06 09:13:15,062 ERROR [http-nio-8080-exec-6] o.a.wicket.MarkupContainer(1476) - Unable to find component with id 'idNomEquipement' in [ListeEquipementReseauLocal [Component id = panelDiagnosticEquipementsReseauxLocal]]
Expected: 'panelDiagnosticEquipementsReseauxLocal.idNomEquipement'.
Found with similar names: 'panelDiagnosticEquipementsReseauxLocal:listeEquipements:1:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:2:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:3:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:4:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:5:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:6:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:7:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:8:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:9:idNomEquipement'
2018-12-06 09:13:15,069 ERROR [http-nio-8080-exec-6] o.a.w.DefaultExceptionMapper(114) - Unexpected error occurred
org.apache.wicket.markup.MarkupException: Unable to find component with id 'idNomEquipement' in [ListeEquipementReseauLocal [Component id = panelDiagnosticEquipementsReseauxLocal]]
Expected: 'panelDiagnosticEquipementsReseauxLocal.idNomEquipement'.
Found with similar names: 'panelDiagnosticEquipementsReseauxLocal:listeEquipements:1:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:2:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:3:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:4:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:5:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:6:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:7:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:8:idNomEquipement', panelDiagnosticEquipementsReseauxLocal:listeEquipements:9:idNomEquipement'
at org.apache.wicket.markup.MarkupStream.throwMarkupException(MarkupStream.java:526) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1477) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderComponentTagBody(MarkupContainer.java:1571) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAssociatedMarkup(MarkupContainer.java:693) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.AssociatedMarkupSourcingStrategy.renderAssociatedMarkup(AssociatedMarkupSourcingStrategy.java:76) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.PanelMarkupSourcingStrategy.onComponentTagBody(PanelMarkupSourcingStrategy.java:112) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRenderComponent(Component.java:2556) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1534) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1432) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderComponentTagBody(MarkupContainer.java:1571) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onComponentTagBody(MarkupContainer.java:1525) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:72) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRenderComponent(Component.java:2556) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1534) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1432) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderComponentTagBody(MarkupContainer.java:1571) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onComponentTagBody(MarkupContainer.java:1525) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:72) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRenderComponent(Component.java:2556) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1534) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1432) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderComponentTagBody(MarkupContainer.java:1571) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onComponentTagBody(MarkupContainer.java:1525) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:72) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRenderComponent(Component.java:2556) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1534) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1432) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderComponentTagBody(MarkupContainer.java:1571) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onComponentTagBody(MarkupContainer.java:1525) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:72) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRenderComponent(Component.java:2556) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1534) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1432) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1596) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Page.onRender(Page.java:907) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.markup.html.WebPage.onRender(WebPage.java:140) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.internalRender(Component.java:2386) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Component.render(Component.java:2314) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.Page.renderPage(Page.java:1035) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:105) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:224) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:167) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:784) ~[wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64) ~[wicket-request-1.5.7.jar:1.5.7]
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:255) [wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:212) [wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:283) [wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:188) [wicket-core-1.5.7.jar:1.5.7]
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:244) [wicket-core-1.5.7.jar:1.5.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
at com.francetelecom.clara.security.filter.SecurityFilter.doFilter(SecurityFilter.java:273) [security-3.1.0.jar:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
at com.francetelecom.clara.security.filter.IpFilter.doFilter(IpFilter.java:70) [security-3.1.0.jar:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.23]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.23]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [catalina.jar:8.0.23]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.23]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.23]
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617) [catalina.jar:8.0.23]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.23]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [catalina.jar:8.0.23]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-coyote.jar:8.0.23]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-coyote.jar:8.0.23]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-coyote.jar:8.0.23]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-coyote.jar:8.0.23]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_191]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.23]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]

I have the feeling you have a Component with wicket:id=idNomEquipe in different part of your application.
The error says ListeEquipes [Component id = panelDiagnosticEquipes], i.e. Wicket tries to find idNomEquipe in panelDiagnosticEquipes, not in listeEquipes (the ListView).

The problem is html you have given name as idNomEquipes in java you have the wicket id as idNomEquipe in the listView change the java name to idNomEquipes it will resolve the issue.

i founded the problem. The problem is the space
<tr class="liste" wicket: id="listeEquipements">.
The space between wicket: and id. wicket doesn't understand the space between wicket: and id.

Related

How Sum input fields values after save in cakephp?

Good afternoon, first of all a cordial greetings to all forum. I have
a problem and need help. Please would be so kind to help me with
information, text, illustrations, to perform mathematical operations
in cakephp, the problem is that I am still a newbie and I was a bit
complicated all this, to get a better idea this is my view
Form view:
http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9234902vistaprevia.jpg
Example:
form:
    3 * 7.50 = 22.50
form:
    4 * 5.50 = 22
form:
    1 * 4.90 = 4.90
form:
    2 * 12.90 = 25.8
total: 72.50
What I want to do is take the amounts written on the forms and then do
the calculation and place in the total field
DB view
http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9234906db.jpg
----------view/add.ctp.........
<div class="ventas form">
<?php echo $this->Form->create('Venta'); ?>
<fieldset>
<legend><?php echo __('PROCESO DE COMPRA'); ?></legend>
<?php
echo $this->Form->input('nombre');
echo $this->Form->input('apellido');
echo $this->Form->input('cedula');
echo $this->Form->input('direccion');
echo $this->Form->input('mail');
echo $this->Form->input('telefono');
echo $this->Form->input('tarjeta');
echo $this->Form->input('numtarjeta');
echo __('<legend>SELECCIONE SU PELICULA</legend>');
echo $this->Form->input('cartelera_id',array('label' => 'Seleccione su pelicula'));
echo $this->Form->input('cant_adulto', array('label' => 'Cantidad de boletos - Precio normal $ 7,50'));
echo $this->Form->input('cant_niño', array('label' => 'Cantidad de boletos - Precio niños/ancianos $ 5,50'));
echo $this->Form->input('cant_discapacitado', array('label' => 'Cantidad de boletos - Precio discapacitados $ 4,90'));
echo __('<legend>SELECCIONE SU COMBO</legend>');
echo $this->Form->input('combo_id');
echo $this->Form->input('numcombo', array('label' => 'Cantidad de combos - Precio discapacitados $ 12,90'));
echo $this->Form->input('total');
?>
</fieldset>
<?php echo $this->Form->end(__('Guardar')); ?>
</div>
.......Controller.......
class VentasController extends AppController {
/** * Components
* * #var array
*/ public $components = array('Paginator');
/** * index method
* * #return void
*/
public function index() {
$this->Venta->recursive = 0;
$this->set('ventas', $this->Paginator->paginate());
}/**
* view method
*
* #throws NotFoundException
* #param string $id
* #return void
*/
public function view($id = null) {
if (!$this->Venta->exists($id)) {
throw new NotFoundException(__('Invalid venta'));
}
$options = array('conditions' => array('Venta.' . $this->Venta->primaryKey => $id));
$this->set('venta', $this->Venta->find('first', $options));
}
/**
* add method *
* #return void */
public function add() {
if ($this->request->is('post')) {
$this->Venta->create();
if ($this->Venta->save($this->request->data)) {
$this->Session->setFlash(__('La venta se almacenó correctamente.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('La venta no se almacenó correctamente. Por favor, Intente de nuevo.'));
}
}
$carteleras = $this->Venta->Cartelera->find('list',array('fields'=>'pelicula'));
$this->set(compact('carteleras'));
$combos = $this->Venta->Combo->find('list',array('fields'=>'nombre'));
$this->set(compact('combos'));
}
/** * edit method
* * #throws NotFoundException
* #param string $id
* #return void
*/ public function edit($id = null) {
if (!$this->Venta->exists($id)) {
throw new NotFoundException(__('Invalid venta'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->Venta->save($this->request->data)) {
$this->Session->setFlash(__('La venta se almacenó correctamente.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('La venta no se almacenó correctamente. Por favor, Intente de nuevo.'));
}
} else {
$options = array('conditions' => array('Venta.' . $this->Venta->primaryKey => $id));
$this->request->data = $this->Venta->find('first', $options);
}
$carteleras = $this->Venta->Cartelera->find('list');
$this->set(compact('carteleras'));
$combos = $this->Venta->Combo->find('list');
$this->set(compact('combos'));
}
/**
* delete method *
* #throws NotFoundException
* #param string $id
* #return void
*/ public function delete($id = null) {
$this->Venta->id = $id;
if (!$this->Venta->exists()) {
throw new NotFoundException(__('Invalid venta'));
}
Thank you very much for your attention
Use the beforeSave() callback of the model. Do your calculation there and write to the field.
Example taken from the book:
public function beforeSave($options = array()) {
if (!empty($this->data['Event']['begindate']) &&
!empty($this->data['Event']['enddate'])
) {
$this->data['Event']['begindate'] = $this->dateFormatBeforeSave(
$this->data['Event']['begindate']
);
$this->data['Event']['enddate'] = $this->dateFormatBeforeSave(
$this->data['Event']['enddate']
);
}
return true;
}
public function dateFormatBeforeSave($dateString) {
return date('Y-m-d', strtotime($dateString));
}
public function vent() {
if ($this->request->is('post')) {
$this->Venta->create();
$this->request->data['Venta']['total'] = ($this->request->data['Venta']
['cant_adulto'] * 7.5) + ($this->request->data['Venta']['cant_niño'] *
5.5) + ($this->request->data['Venta']['cant_discapacitado'] * 4.9)+
($this->request->data['Venta']['numcombo'] * 12.9) ;
if ($this->Venta->save($this->request->data)) {
$this->Session->setFlash(__('La venta se almacenó correctamente.'));
$inserted_id=$this->Venta->id;
return $this->redirect(array('action' => 'view', $inserted_id));
} else {
$this->Session->setFlash(__('La venta no se almacenó correctamente. Por
favor, Intente de nuevo.'));
}}
$carteleras = $this->Venta->Cartelera-
>find('list',array('fields'=>'pelicula'));
$this->set(compact('carteleras'));
$combos = $this->Venta->Combo->find('list',array('fields'=>'nombre'));
$this->set(compact('combos'));
}

CheckBoxCell in CellTable

I have a CheckBoxCell I want to add my CellTable but not when I'm wrong because when I run it does not show me the Check
THIS IS MY CODE
public class TablaEntryPoint extends Composite implements EntryPoint{
private SingleSelectionModel sm = new SingleSelectionModel();
{
// Añade un objeto que recibe notificaciones cuando cambia la selección.
sm.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
AuxParametro c = sm.getSelectedObject();
if (c != null) {
Window.alert(c.getNomParametro());
}
}
});
}
/** La tabla trabaja por páginas. En este caso la longitud de página se pasa en el
* constructor. También hay un constructor sin parámetros que define una longitud
* por defecto de 15 renglones por página. */
private final CellTable<AuxParametro> tblConocidos = new CellTable<AuxParametro>(10);
{
// asigna el objeto que controla las selecciones.
tblConocidos.setSelectionModel(sm);
// Agrega columnas.
// Columna numérica. El constructor de "NumberCell"puede recibir un"NumberFormat".
tblConocidos.addColumn(new Column<AuxParametro, Number>(new NumberCell()) {
{
setHorizontalAlignment(HasAlignment.ALIGN_RIGHT);
}
#Override
public Long getValue(final AuxParametro objeto) {
return objeto.getIdParametro();
}
}, "ID Unico");
// Columna de texto fijo con encabezado y pie de página.
tblConocidos.addColumn(new TextColumn<AuxParametro>() {
#Override
public String getValue(final AuxParametro objeto) {
return objeto.getNomParametro();
}
}, "Nombre Parametro");
/* Columna modificable. El método "update" de la interfaz "FieldUpdater" recibe
* los cambios a un objeto de la columna. */
tblConocidos.addColumn(new Column<AuxParametro,String>(new TextInputCell()) {
{
/* Asigna la referencia al objeto que recibe las notificaciones de cambio. */
setFieldUpdater(new FieldUpdater<AuxParametro, String>() {
#Override
public void update(int index, AuxParametro objeto, String valor) {
objeto.setCodContable(Integer.parseInt(valor));
}
});
}
#Override
public String getValue(final AuxParametro objeto) {
return String.valueOf(objeto.getCodContable());
}
}, "Codigo Contable");
// Columna de fecha.
tblConocidos.addColumn(new Column<AuxParametro, Number>(new NumberCell()) {
#Override
public Integer getValue(final AuxParametro objeto) {
return objeto.getCodUno();
}
}, "Codigo Uno");
// Columna de fecha.
tblConocidos.addColumn(new Column<AuxParametro, Number>(new NumberCell()) {
#Override
public Integer getValue(final AuxParametro objeto) {
return objeto.getCodDos();
}
}, "Codigo Dos");
Column<AuxParametro, Boolean> checkColumn = new Column<AuxParametro, Boolean>(
new CheckboxCell(true, false)) {
#Override
public Boolean getValue(AuxParametro object) {
// Get the value from the selection model.
return sm.isSelected(object);
}
};
tblConocidos.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
}
private final SimplePager pager = new SimplePager();
{
pager.setDisplay(tblConocidos);
}
public TablaEntryPoint(List<AuxParametro> tabla) {
ListDataProvider<AuxParametro> dataProvider = new ListDataProvider<AuxParametro>(tabla);
dataProvider.addDataDisplay(tblConocidos);
FlowPanel panel = new FlowPanel();
panel.add(new Label("Seleccione un contacto o edite su teléfono."));
panel.add(tblConocidos);
panel.add(pager);
initWidget(panel);
}
public void onModuleLoad() {
RootPanel.get().add(this);
}
}
I think you need to set the column width for each of your columns. If you look at the GWT showcase CellTable example (here) you can see that the checkbox column width is set with the statement cellTable.setColumnWidth(checkColumn, 40, Unit.PX).

Android GCM crashes when app is stopped

I’m trying to implement an Android app with GCM (Google Cloud Messaging).
My specific Server is written by PHP and my Client is an Android app.
Push notification messages are received well when the app is running. The logcat is this:
07-28 07:49:56.991: V/GCMBroadcastReceiver(13254): onReceive: com.google.android.c2dm.intent.RECEIVE
07-28 07:49:56.991: V/GCMRegistrar(13254): Setting the name of retry receiver class to com.appacoustic.android.g.gcm.GGCMBroadcastReceiver
07-28 07:49:57.011: D/GGCMBroadcastReceiver(13254): Servicio: com.appacoustic.android.g.gcm.GGCMIntentService
07-28 07:49:57.011: V/GCMBroadcastReceiver(13254): GCM IntentService class: com.appacoustic.android.g.gcm.GGCMIntentService
07-28 07:49:57.021: V/GCMBaseIntentService(13254): Intent service name: GCMIntentService-<<<MyProjectNumber>>>-1
07-28 07:49:57.026: D/GGCMIntentService(13254): Mensaje recibido: <<<MySendedMessage>>>
but when it is stopped (not paused), if I send a message from the host, appears the typical Toast crash.
The logcat error is this:
07-28 07:50:06.381: V/GCMBroadcastReceiver(13294): onReceive: com.google.android.c2dm.intent.RECEIVE
07-28 07:50:06.386: V/GCMRegistrar(13294): Setting the name of retry receiver class to com.appacoustic.android.g.gcm.GGCMBroadcastReceiver
07-28 07:50:06.386: D/GGCMBroadcastReceiver(13294): Servicio: com.appacoustic.android.g.gcm.GGCMIntentService
07-28 07:50:06.386: V/GCMBroadcastReceiver(13294): GCM IntentService class: com.appacoustic.android.g.gcm.GGCMIntentService
07-28 07:50:06.396: D/AndroidRuntime(13294): Shutting down VM
07-28 07:50:06.396: W/dalvikvm(13294): threadid=1: thread exiting with uncaught exception (group=0x4163bc50)
07-28 07:50:06.401: E/AndroidRuntime(13294): FATAL EXCEPTION: main
07-28 07:50:06.401: E/AndroidRuntime(13294): Process: com.planetdevices.android.loyalty, PID: 13294
07-28 07:50:06.401: E/AndroidRuntime(13294): java.lang.RuntimeException: Unable to instantiate service com.appacoustic.android.g.gcm.GGCMIntentService: java.lang.NullPointerException
I guess the issue is about wake up the Service, but actually I test too much things and I am really confused and exhausted…
I have made a package in a library project to implement GCM. The code is this:
GGCMIntentService.java
package com.appacoustic.android.g.gcm;
...
/**
* #author AppAcoustiC <p>
* Servicios GCM. Básicamente son todo callbacks.
*/
public class GGCMIntentService extends GCMBaseIntentService {
private static final String tag = "GGCMIntentService";
/**
* Constructor.
*/
public GGCMIntentService() {
super(SENDER_ID); // Llamamos a la superclase
} // GGCMIntentService()
/**
* Es lo que hace al registrarse el dispositivo.
*/
#Override
protected void onRegistered(Context context, String registrationId) {
Log.i(tag, "Dispositivo registrado: regId = " + registrationId);
Log.d("name: ", GGCM.name);
Log.d("email: ", GGCM.email);
displayMessage(context, getString(R.string.gcm_registered)); // Mostramos un mensaje informativo por pantalla
GServerUtilities.register(context, registrationId, GGCM.name, GGCM.email); // Nos registramos en nuestro Servidor dedicado (Planet Devices)
} // onRegistered()
/**
* Es lo que se hace al eliminar el registro.
*/
#Override
protected void onUnregistered(Context context, String registrationId) {
Log.i(tag, "Eliminado el registro del dispositivo.");
displayMessage(context, getString(R.string.gcm_unregistered)); // Mostramos un mensaje informativo por pantalla
if (GCMRegistrar.isRegisteredOnServer(context)) { // Si ya está registrado en nuestro Servidor
GServerUtilities.unregister(context, registrationId); // Se desregistra de éste
} else {
// Este callback se hace al tratar de borrar el registro desde la clase ServerUtilities cuando el registro en el Servidor falla
Log.i(tag, "Se ha ignorado el callback de anulación de registro.");
}
} // onUnregistered()
/**
* Notificación recibida.
*/
#Override
protected void onMessage(Context context, Intent intent) {
String message = intent.getStringExtra(GCommonUtilities.EXTRA_MESSAGE); // Recojo el mensaje
Log.d(tag, "Mensaje recibido: " + message);
displayMessage(context, message); // Lo mostramos por pantalla
generateNotification(context, message); // Se lo notificamos al usuario (mensaje emergente)
} // onMessage()
/**
* Cuando se borran los mensajes.
*/
#Override
protected void onDeletedMessages(Context context, int total) {
Log.i(tag, "Recibida la notificación de mensajes eliminados.");
String message = getString(R.string.gcm_deleted, total); // Recojo el string y el nº de mensajes borrados SERÁ SIEMPRE EL MISMO STRING AL COGERLO DE LOS R.STRING ???
displayMessage(context, message); // Lo mostramos por pantalla
generateNotification(context, message); // Se lo notificamos al usuario (mensaje emergente)
} // onDeletedMessages()
/**
* Al producirse un error.
*/
#Override
public void onError(Context context, String errorId) {
Log.i(tag, "Error recibido: " + errorId);
displayMessage(context, getString(R.string.gcm_error, errorId)); // Lo mostramos por pantalla
} // onError()
/**
* Al producirse un error recuperable.
*/
#Override
protected boolean onRecoverableError(Context context, String errorId) {
Log.i(tag, "Recibido error recuperable: " + errorId);
displayMessage(context, getString(R.string.gcm_recoverable_error, errorId)); // Lo mostramos por pantalla
return super.onRecoverableError(context, errorId); // Devolvemos un booleano para saber como ha ido la cosa
} // onRecoverableError()
/**
* Genera una notificación para que el usuario sea informado de que ha recibido un mensaje.
*/
private static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_launcher; // Icono que aparece en la barra de notificaciones (será el de la app desde donde creemos el objeto GGCM)
long when = System.currentTimeMillis(); // Instante en el que se produce la notificación
// Creamos la notificación:
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name); // Título de la notificación (Nombre de la app)
// Gestionamos el Intent de la notificación:
Intent notificationIntent = new Intent(context, GGCM.NotificationActivity); // Lo configuramos para que empiece una nueva Actividad (NotificationActivity)
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND; // Sonido de notificación por defecto
// ¡¡¡ POR SI QUEREMOS USAR NUESTRO PROPIO SONIDO PERSONALIZADO !!!
//notification.sound = Uri.parse("android.resource://" + context.getPackageName() + "your_sound_file_name.mp3");
notification.defaults |= Notification.DEFAULT_VIBRATE; // Vibra (si la vibración está activa, claro)
notificationManager.notify(0, notification); // Notificamos (con todos los parámetros incluidos)
} // generateNotification()
} // GGCMIntentService
GGCM.java
package com.appacoustic.android.g.gcm;
...
/**
* #author AppAcoustiC <p>
* Engloba todo lo que conlleva el sistema Google Cloud Messaging.
*/
public class GGCM {
private final String tag = "GGCM";
private Context context;
// Variables que meteremos en la base de datos de nuestro Servidor particular:
static String name;
static String email;
static Class<?> NotificationActivity;
AsyncTask<Void, Void, Void> mRegisterTask; // Tarea de registro
AsyncTask<Void, Void, Void> mUnregisterTask; // Tarea de eliminación del registro
/**
* Constructor.
* #param context Contexto de la Actividad.
* #param SERVER_URL Base URL del Servidor (directorio raíz).
* #param SENDER_ID ID del proyecto en cuestión registrado para usar GCM.
* #param userName Nombre del usuario de la aplicación.
* #param cls Actividad que se inicia al pulsar las notificaciones recibidas.
*/
public GGCM(final Context context,
String SERVER_URL,
String SENDER_ID,
String userName,
Class<?> cls) {
// Primero de nada, comprobamos que está todo en orden para que el GCM funcione.
// Qué el dispositivo soporta GCM y que el Manifest está bien configurado. Esto, una vez testeado se puede comentar:
//checker(context);
// Comprobacion rutinaria de que tenemos inicializadas la variables que indican el Servidor y el ID del proyecto GCM:
G_A.checkNotNull(SERVER_URL, "SERVER_URL");
G_A.checkNotNull(SENDER_ID, "SENDER_ID");
// Asignamos los parámetros a las variables que usamos dentro del paquete:
this.context = context;
GCommonUtilities.SERVER_URL = SERVER_URL;
GCommonUtilities.SENDER_ID = SENDER_ID;
name = userName;
email = G_A.getEmailAdress(context);
NotificationActivity = cls;
// Comprobamos la conexión a internet:
GConnectionDetector gCD = new GConnectionDetector(context);
if (!gCD.isConnectingToInternet()) { // Si no hay internet
// Creamos nuestro Diálogo de alerta particular
GAlertDialog.showAlertDialog(context,
"Error de conexión a Internet",
"Por favor, conéctese para poder hacer uso de la aplicación.",
false);
return; // Paramos la ejecución del programa
}
context.registerReceiver(mHandleMessageReceiver, new IntentFilter(GCommonUtilities.DISPLAY_MESSAGE_ACTION)); // Registramos el receptor
} // GGCM()
/**
* Registra el dispositivo en el que está instalada la app.
*/
public void registerDevice() {
final String regId = GCMRegistrar.getRegistrationId(context); // Obtenemos el ID de registro
if (regId.equals("")) { // Si es "" es que aún no estamos registrados
GCMRegistrar.register(context, GCommonUtilities.SENDER_ID); // Nos registramos
Log.i(tag, "Nos acabamos de registrar en el GCM.");
} else {
// El dispositivo ya está registrado. Comprobamos el Servidor:
if (GCMRegistrar.isRegisteredOnServer(context)) {
// Nos saltamos el registro en el Servidor. Simplemente mostramos un mensaje por pantalla:
G_A.showToast(context, context.getString(R.string.already_registered), Toast.LENGTH_SHORT);
Log.i(tag, "Ya está registrado en nuestro Servidor.");
} else {
// Tratamos de registrarnos de nuevo. Hay que hacerlo mediante una Tarea Asíncrona:
mRegisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
boolean registered = GServerUtilities.register(context, regId, name, email);
// Si llegados a este punto, todos los intentos de registrar el dispositivo a nuestro Servidor (Planet Devices) fallan,
// necesitaremos desregistrar el dispositivo desde GCM. La aplicación tratará de registrarse de nuevo cuando se reinicie.
// Hay que tener en cuenta que GCM enviará una devolución de llamada (callback) de borrado de registro al finalizar,
// pero GGCMIntentService.onUnregistered() lo ignorará:
if (!registered) {
GCMRegistrar.unregister(context); // Eliminamos el registro
}
return null;
} // doInBackground()
#Override
protected void onPostExecute(Void result) {
mRegisterTask = null; // Liberamos memoria
} // onPostExecute()
};
mRegisterTask.execute(null, null, null); // Ejecutamos la tarea
}
}
} // registerDevice()
/**
* Elimina el registro del dispositivo que tiene instalada la aplicación.
*/
public void unregisterDevice() {
final String regId = GCMRegistrar.getRegistrationId(context); // Obtenemos el ID de registro
//GServerUtilities.unregister(context, regId);
if (regId.equals("")) { // Si es "" es que aún no estamos registrados
Log.i(tag, "Nos estamos aún registrados. No se puede anular el registro.");
G_A.showToast(context, context.getString(R.string.already_unregistered), Toast.LENGTH_SHORT); // ESTO NO FUNCIONA COMO BEBERÍA !!!
} else {
// Tratamos de eliminar el registro. Hay que hacerlo mediante una Tarea Asíncrona:
mUnregisterTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
GServerUtilities.unregister(context, regId); // Nos "desregistramos"
return null;
} // doInBackground()
#Override
protected void onPostExecute(Void result) {
mUnregisterTask = null; // Liberamos memoria
} // onPostExecute()
};
mUnregisterTask.execute(null, null, null); // Ejecutamos la tarea
}
} // unregisterDevice()
/**
* Comprobamos si el dispositivo soporta GCM y que el Manifest está bien configurado.
*/
private void checker(Context context) {
try {
GCMRegistrar.checkDevice(context);
Log.i(tag, "El dispositivo soporta GCM.");
GCMRegistrar.checkManifest(context);
Log.i(tag, "El Manifest está correctamente.");
} catch (UnsupportedOperationException e) {
Log.e(tag, "El dispositivo no soporta GCM.", e);
} catch (IllegalStateException e) {
Log.e(tag, "El Manifest no está bien configurado.", e);
}
} // checker()
/**
* Manejador para recibir mensajes.
*/
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(GCommonUtilities.EXTRA_MESSAGE); // Recogemos el mensaje
GWakeLocker.acquire(context); // Mantenemos el dispositivo a la espera de que acabe de procesar todo el mensaje (para que no entre en modo de suspensión)
// SI TENEMOS ESTO PUESTO MUESTRA TOAST CADA VEZ QUE ENVIAMOS UNA NOTIFICACIÓN PUSH !!!!!:
//G_A.showToast(context, newMessage, Toast.LENGTH_SHORT); // Lo mostramos por pantalla
GWakeLocker.release(); // Liberamos para ahorrar energía (importante para optimizar los recursos de la batería)
} // onReceive()
};
/**
* Realiza las acciones pertinentes cuando se hace un callback de onDestroy desde la Actividad que llama al objeto GGCM.
*/
public void setOnDestroy() {
if (mRegisterTask != null) {
mRegisterTask.cancel(true); // Cancelamos la Tarea de registro
}
context.unregisterReceiver(mHandleMessageReceiver); // Desregistramos el manejador de mensajes ?????????????????? ESTO CREO QUE HAY QUE QUITARLO, SINO NO LLEGARÁN LOS MENSAJES EMERGENTES
GCMRegistrar.onDestroy(context); // Destruimos
} // setOnDestroy()
} // GGCM
GCommonUtilities.java
package com.appacoustic.android.g.gcm;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* #author AppAcoustiC <p>
* Utilidades comunes a todo el paquete. Las cargamos en el contructor de GGCM al hacer la llamada.
*/
public final class GCommonUtilities {
static String SERVER_URL; // Base URL del Servidor
static String SENDER_ID; // ID del proyecto en cuestión registrado para usar GCM
// Intentos usados para mostrar un mensaje en la pantalla:
static final String DISPLAY_MESSAGE_ACTION = "com.appacoustic.android.g.gcm.DISPLAY_MESSAGE"; // Nombre del paquete
static final String EXTRA_MESSAGE = "message"; // Extra
/**
* Notifica a la interfaz de usuario (UI) que tiene que mostrar un mensaje.<p>
* Este método está definido en el Helper común porque es usado por ambos: la interfaz de usuario y el Servicio.
* #param context Contexto de la actividad.
* #param message Mensaje a mostrar.
*/
static void displayMessage(Context context, String message) {
Intent intent = new Intent(DISPLAY_MESSAGE_ACTION); // Instanciamos el intento
intent.putExtra(EXTRA_MESSAGE, message); // Añadimos el mensaje que hemos metido como parámetro
context.sendBroadcast(intent); // Hace el envío asíncrono
} // displayMessage()
} // GCommonUtilities
GGCMBroadcastReceiver.java
package com.appacoustic.android.g.gcm;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.android.gcm.GCMBroadcastReceiver;
/**
* #author AppAcoustiC <p>
* Implementa el receptor de GCM.<p>
* De este modo irá al paquete donde tenemos nosotros nuestro GCMIntentService.
*/
public class GGCMBroadcastReceiver extends GCMBroadcastReceiver {
private final String tag = "GGCMBroadcastReceiver";
/**
* Devuelve el nombre de la clase donde tenemos implementado el servicio.
*/
#Override
protected String getGCMIntentServiceClassName(Context context) {
String s = GGCMIntentService.class.getName();
Log.d(tag, "Servicio: " + s);
return s;
} // getGCMIntentServiceClassName()
} // GGCMBroadcastReceiver
GServerUtilities.java
package com.appacoustic.android.g.gcm;
...
import com.appacoustic.android.g.R;
import com.google.android.gcm.GCMRegistrar;
/**
* #author AppAcoustiC <p>
* Utilidades de comunicación con nuestro Servidor (Planet Devices).
*/
public final class GServerUtilities {
private static final String TAG = "GServerUtilities";
private static final int MAX_ATTEMPTS = 5; // Nº máximo de intentos
private static final int BACKOFF_MILLI_SECONDS = 2000; // Tiempo para echarse atrás
private static final Random random = new Random(); // Objeto auxiliar para generar números aleatorios
/**
* Registra el dispositivo en nuestro Servidor.
* #param context Contexto de la Actividad.
* #param regId ID de registro.
* #param name Nombre del usuario.
* #param email Email del usuario.
* #return Si el registro ha sido correcto.
*/
static boolean register(final Context context, final String regId, String name, String email) {
Log.i(TAG, "Registrando dispositivo... (regId = " + regId + ")");
String serverUrl = SERVER_URL + "/register.php"; // Dirección donde tenemos el *.php que implementa el registro
// Parámetros:
Map<String, String> params = new HashMap<String, String>();
params.put("regId", regId); // ID de registro
params.put("name", name); // Nombre
params.put("email", email); // Email
long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000); // Tiempo para echarse atrás (y un poco más cada vez)
// Una vez GCM devuelve el ID de registro, necesitamos registrar dicho ID en nuestro Servidor particular:
for (int i = 1; i <= MAX_ATTEMPTS; i++) { // Si el Servidor ha caído, lo volveremos a intentar alguna vez más
Log.d(TAG, "Intento de registro nº " + i + ".");
try {
displayMessage(context, context.getString(R.string.server_registering, i, MAX_ATTEMPTS)); // Mostramos por pantalla
post(serverUrl, params); // Hacemos el post con los parámetros hacia nuestro Servidor
GCMRegistrar.setRegisteredOnServer(context, true); // Indicamos que se registra
// Mostramos por pantalla que todo ha ido bien:
String message = context.getString(R.string.server_registered);
GCommonUtilities.displayMessage(context, message);
return true;
} catch (IOException e) {
// Aquí estamos simplificando el manejo de errores. En una aplicación real
// se debería de volver a procesar sólo los errores recuperables (como HTTP error code 503, e.g.):
Log.e(TAG, "Fallo tratando de registrarse. Nº de intento: " + i, e);
if (i == MAX_ATTEMPTS) {
break; // Si ya hemos gastado todos los intentos, paramos la aplicación
}
try {
Log.d(TAG, "Parando por " + backoff + " ms antes de volver a intentar.");
Thread.sleep(backoff); // Retardo
} catch (InterruptedException e1) {
Log.d(TAG, "Hilo interrumpido: Abortamos los restantes intentos.");
Thread.currentThread().interrupt(); // Actividad terminada antes de que la hayamos completado
return false;
}
backoff *= 2; // Incrementamos exponencialemente el tiempo de espera
}
}
// Si hemos llegado hasta aquí es porque hemos condumido todos los intentos.
// Mostramos que ha habido un error:
String message = context.getString(R.string.server_register_error, MAX_ATTEMPTS);
GCommonUtilities.displayMessage(context, message);
return false;
} // register()
/**
* Anula el registro del par "cuenta-dispositivo" en nuestro Servidor.
* #param context Contexto de la Actividad.
* #param regId ID de registro.
*/
static void unregister(final Context context, final String regId) {
Log.i(TAG, "Anulando el registro del dispositivo... (regId = " + regId + ")");
String serverUrl = SERVER_URL + "/unregister.php"; // Archivo *.php encargado de implementar el proceso
// Parámetros:
Map<String, String> params = new HashMap<String, String>();
params.put("regId", regId); // Sólo hace falta el ID de registro para eliminarlo
try {
post(serverUrl, params); // Hacemos el post con los parámetros hacia nuestro Servidor
GCMRegistrar.setRegisteredOnServer(context, false); // Indicamos que se desregistra
// Mostramos por pantalla que todo ha ido bien:
String message = context.getString(R.string.server_unregistered);
GCommonUtilities.displayMessage(context, message);
} catch (IOException e) {
// En este punto, el dispositivo está desregistrado de GCM, pero permanece registrado en nuestro Servidor de Planet Devices.
// Podríamos tratar de anular el registro de nuevo, pero no es necesario, ya que si el Servidor trata de enviar un mensaje al dispositivo,
// se generará un mensaje de error tipo "No registrado" y se debería de anular el registro del dispositivo.
// Mostramos que ha habido un error anulando el registro:
String message = context.getString(R.string.server_unregister_error, e.getMessage());
GCommonUtilities.displayMessage(context, message);
}
} // unregister()
/**
* Realiza un POST a nuestro Servidor.
* #param endpoint Dirección del POST.
* #param params Parámetros de la solicitud.
* #throws IOException
*/
private static void post(String endpoint, Map<String, String> params) throws IOException {
URL url; // Dirección del POST
try {
url = new URL(endpoint); // La inicializamos
} catch (MalformedURLException e) {
throw new IllegalArgumentException("URL incorrecta: " + endpoint); // La dirección no es correcta
}
// Creamos un StringBuilder para cargar el contenido del POST:
StringBuilder bodyBuilder = new StringBuilder();
Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
// Construimos el cuerpo del POST usando los parámetros:
while (iterator.hasNext()) {
Entry<String, String> param = iterator.next();
bodyBuilder.append(param.getKey()).append('=').append(param.getValue());
if (iterator.hasNext()) {
bodyBuilder.append('&');
}
}
String body = bodyBuilder.toString(); // Pasamos a un único String todo el StringBuilder
Log.v(TAG, "Enviando '" + body + "' a " + url);
byte[] bytes = body.getBytes(); // Convertimos a bytes para que puedan viajar por la red mdiante un Stream
HttpURLConnection conn = null; // Conexión
try {
// Abrimos la conexión y la configuramos:
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setFixedLengthStreamingMode(bytes.length);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
// Posteamos la solicitud:
OutputStream out = conn.getOutputStream(); // Instanciamos el flujo
out.write(bytes); // Enviamos los datos
out.close(); // Cerramos el Stream
// Manejamos la respuesta:
int status = conn.getResponseCode(); // Obtenemos el código de respuesta desde el Servidor (el 200 indica que todo ha ido bien)
if (status != 200) { // Si no es el código 200, es porque ha habido un error
throw new IOException("Envío fallido con error de código: " + status);
}
} finally {
if (conn != null) {
conn.disconnect(); // Al final desconectamos
}
}
} // post()
} // GServerUtilities
I have written an Android app which calls the library like that:
Call in onCreate()
// Creamos nuestro objeto GCM:
gGCM = new GGCM(context,
Att.SERVER_URL,
Att.SENDER_ID,
Att.userName,
NotificationActivity.class);
//gGCM.registerDevice(); // Nos registramos directamente
//gGCM.unregisterDevice();
I have a NotificationActivity which is the Activity which is thrown when you click the push notification and so on...
Finally my Manifest is here:
AndroidMainfest.xml
...
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET"/>
<!-- GCM requiere de una cuenta Google -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Se activa cuando se recibe un mensaje -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Crea un permiso específico para este paquete. Sólo esta app puede recibir estos mensajes -->
<permission
android:name="com.planetdevices.android.loyalty.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.planetdevices.android.loyalty.permission.C2D_MESSAGE" />
<!-- Esta aplicación tiene permiso para registrarse y recibir mensajes de datos de Google -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Pemisos del estado de la red para detectar el status de Internet -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Vibración -->
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="Splash"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/Splash" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="MainActivity" android:screenOrientation="portrait"></activity>
<activity android:name="NotificationActivity" android:screenOrientation="portrait"></activity>
...
<!-- Receptor -->
<receiver
android:name="com.appacoustic.android.g.gcm.GGCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.appacoustic.android.g.gcm" />
</intent-filter>
</receiver>
<!-- Servicio -->
<service android:name="com.appacoustic.android.g.gcm.GGCMIntentService" />
</application>
</manifest>
Thank you so much for your help!
I’ve changed calling to SuperClass Constructor in GGCMIntentService. I have put directly the SENDER_ID as a String with its value. I have done it because when I stop the app, when that Constructor is called, throws a nullPointerException, because String “SENDER_ID” is not initialized.
public GGCMIntentService() {
//super(SENDER_ID); // Llamamos a la superclase
super("<<<ProjectNumber>>>"); // NEW WAY
} // GGCMIntentService()
After that, for a similar reason, I’ve put also directly Activity to start in the same Class in method generateNotification() like this:
Class<?> cls = null;
try {
cls = Class.forName("<<<packageName>>>.NotificationActivity");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
I have put this instance a little lines below:
Intent notificationIntent = new Intent(context, cls);
It’s not the best solution, but it works perfectly whenever. :-)

EJB3.1 JSF2.0 CDI ejbRef conversion

I am developping a project using JSF2.0/Primefaces, EJB3.1, Hibernate.
I created an enterprise application, injected EJB3 Facades into JSF Managed Beans using CDI and created web pages that call the managed beans. When i run the project i am able to list data rows and view row details but the problem appears when i select one row from the datatable and click edit or remove button.
SEVERE: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.procc.jpa.Alert.responseCollection, could not initialize proxy - no Session
SEVERE: java.lang.IllegalStateException: Unable to convert ejbRef for ejb AlertFacade to a business object of type interface com.procc.dao.AlertFacadeLocal
at com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:114)
at org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:63)
at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:108)
at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105)
at com.procc.dao.AlertFacade$Proxy$_$$_Weld$Proxy$.remove(AlertFacade$Proxy$_$$_Weld$Proxy$.java)
at com.procc.backing.AlertController.persist(AlertController.java:118)
at com.procc.backing.AlertController.delete(AlertController.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.sun.el.parser.AstValue.invoke(AstValue.java:254)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:148)
at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:769)
at javax.faces.component.UICommand.broadcast(UICommand.java:300)
at javax.faces.component.UIData.broadcast(UIData.java:1093)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
This is code snippet:
#ManagedBean(name = "alertController")
#SessionScoped
public class AlertController extends AbstractController<Alert> implements Serializable {
#Inject private AlertFacadeLocal ejbFacade;
private Class<Alert> itemClass;
private Alert selected;
private List<Alert> items;
private enum PersistAction {
CREATE,
DELETE,
UPDATE
}
public AlertController(){
itemClass = Alert.class;
}
public void delete(ActionEvent event) {
String msg = ResourceBundle.getBundle("/Bundle").getString(itemClass.getSimpleName() + "Deleted");
persist(AlertController.PersistAction.DELETE, msg);
if (!isValidationFailed()) {
selected = null; // Remove selection
items = null; // Invalidate list of items to trigger re-query.
}
}
private void persist(AlertController.PersistAction persistAction, String successMessage) {
if (selected != null) {
this.setEmbeddableKeys();
try {
if (persistAction != AlertController.PersistAction.DELETE) {
this.ejbFacade.edit(selected);
} else {
this.ejbFacade.remove(selected);
}
JsfUtil.addSuccessMessage(successMessage);
} catch (EJBException ex) {
String msg = "";
Throwable cause = JsfUtil.getRootCause(ex.getCause());
if (cause != null) {
msg = cause.getLocalizedMessage();
}
if (msg.length() > 0) {
JsfUtil.addErrorMessage(msg);
} else {
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
}
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
}
}
}
In JSF page i got:
<p:panel header="#{bundle.ListAlertTitle}" style="border:0px;">
<p:dataTable id="datalist" value="#{alertController.items}" var="item"
selectionMode="single" selection="#{alertController.selected}"
rowKey="#{item.alertId}"
paginator="true"
rows="10"
rowsPerPageTemplate="10,20,30"
>
<p:ajax event="rowSelect" update="viewButton editButton deleteButton"/>
<p:ajax event="rowUnselect" update="viewButton editButton deleteButton"/>
<p:column sortBy="#{item.alertId}" filterBy="#{item.alertId}">
<f:facet name="header">
<h:outputText value="#{bundle.ListAlertTitle_alertId}"/>
</f:facet>
<h:outputText value="#{item.alertId}"/>
</p:column>
....
<p:commandButton id="viewButton" icon="ui-icon-search" value="#{bundle.View}" update=":AlertViewForm" oncomplete="AlertViewDialog.show()" disabled="#{empty alertController.selected}"/>
<p:commandButton id="editButton" icon="ui-icon-pencil" value="#{bundle.Edit}" update=":AlertEditForm" oncomplete="AlertEditDialog.show()" disabled="#{empty alertController.selected}"/>
<p:commandButton id="deleteButton" icon="ui-icon-trash" value="#{bundle.Delete}" actionListener="#{alertController.delete}" update=":growl,datalist" disabled="#{empty alertController.selected}"/>
Strange error!
I tryed to do an explicit conversion to AirportFacade and that solved the problem!! I don't know why could'nt it do the implicit conversion? and why does it need conversion from first place ??
if (persistAction != PersistAction.DELETE) {
((AirportFacade)ejbFacade).edit(selected);
} else {
((AirportFacade)ejbFacade).remove(selected);
}
Please, if anybody got the answer let me know.
Thanks.

Customized GridView - AddCustomControlsRow on PreRender empties DataRows

I´m trying to create a custom GridView with additional functionality but I do have problem with PostBack which are "simulated" by "Button2". On every PostBack (after a first DataBinding) the content of one DataRow gets erased until the GridView is fully empty. It has something to do with AddCustomControls() within the PreRender event. But I don´t know how to fix this issue. Does anybody have an idea? Any help would be greatly appreciated.
Maybe the image below describes the behavior better than my words do.
With DataBind() in the OnLoad event and AddCustomControls in the OnDataBound event it worked pretty well. The table stayed exactly the same between PostBacks. But I couldn´t use this "solution" (which is also not very elegant) anymore when I tried to implement the editing of the grid. Logically the edited values within the TextBoxes were overriden by the DataBind() in OnLoad.
Somehow it has to do with "headerTable.Rows.AddAt(1, controlRow);". If I do "headerTable.Rows.Add(controlRow);" which adds the row at the end everything works finde. So the content AFTER this kind of header row get cleared...
Web.config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<pages>
<controls>
<add tagPrefix="asp" assembly="WebApplication11" namespace="WebApplication11"/>
</controls>
</pages>
</system.web>
</configuration>
Default.aspx
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:mightygridview
ID="mightyGridView"
runat="server"
AllowSorting="true"
AllowHiding="true"
AutoGenerateEditButton="false"
OnRowUpdating="mightyGridView_RowUpdating">
</asp:mightygridview>
<br />
<asp:Button ID="Button1" runat="server" Text="Button - Binding" onclick="Button1_Click" />
<asp:Button ID="Button2" runat="server" Text="Button - Nothing" />
</div>
</form>
</body>
</html>
Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
DataTable tbl = new DataTable();
DataRow row;
tbl.Columns.Add("Spalte A");
tbl.Columns.Add("Spalte B");
tbl.Columns.Add("Spalte C");
row = tbl.NewRow();
row[0] = "Spalte A, Zeile 1";
row[1] = "Spalte B, Zeile 1";
row[2] = "Spalte C, Zeile 1";
tbl.Rows.Add(row);
row = tbl.NewRow();
row[0] = "Spalte A, Zeile 2";
row[1] = "Spalte B, Zeile 2";
row[2] = "Spalte C, Zeile 2";
tbl.Rows.Add(row);
row = tbl.NewRow();
row[0] = "Spalte A, Zeile 3";
row[1] = "Spalte B, Zeile 3";
row[2] = "Spalte C, Zeile 3";
tbl.Rows.Add(row);
mightyGridView.DataSource = tbl;
mightyGridView.DataBind();
}
MightyGridView.cs
public class MightyGridView : GridView
{
public MightyGridView()
{
_images = new Dictionary<_imageTypes, string>();
_images.Add(_imageTypes.SortAsc, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAAd0SU1FB9oGEAstLlCBjxcAAABWSURBVBjTY/z45TsDqYCFkYF0wMTAyMiADW/ese8/LjkmbCZt3r73PzKNYRMjAwMDMkZXuHn73v/oalBs2oTDZHRxJph2XBpQNELVMn759pOM0CMDAADRtiJL6bIYOQAAAABJRU5ErkJggg==");
_images.Add(_imageTypes.SortAscActive, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9oHDgckDaeYtVQAAAA1SURBVBjTY/z//z8DqYCJgQyAU5NK2Yb/JGmCacClkYmQDdg0MhHjJHRxJmL8gC7PSLcgBwAAMRqcsjcZIwAAAABJRU5ErkJggg==");
_images.Add(_imageTypes.SortDesc, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAAd0SU1FB9oGEAstDmvvr98AAABhSURBVBjTY/zy7ScDqYCJgQzA8p/hPwMDAwPDpm17/xNS7OflzAix6T8DA8N/BgY/T4gATg2ezowwtUwYErg0IPsJqhmOfdEU+Ho6M6KrwRoQMI2+OGxm/PTlOzmhRzoAADvsH5oZ616EAAAAAElFTkSuQmCC");
_images.Add(_imageTypes.SortDescActive, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9oHDgckFi39fLgAAABBSURBVBjTY/z//z8DqYCJgQzAAmOolG0gaOWdrgBGFJtgAoQ0YDgPl0Z0cSZCCrAa9P//f6xYuXT9f1xyjHQLcgCoNDp3uWsOTwAAAABJRU5ErkJggg==");
_images.Add(_imageTypes.HideColumn, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9oGEAsyFSzQaK0AAADHSURBVBjThZAxCoNQDIbTnsAbCM4eQfAC4uYstCdwFOd2dXNwFZzcxQtI3+bkrIKz4AW+Ln2l7WtpIJB8yf9DIoAAsq4rVVWx77topnMcR6ZpQvdHecS2bXJTSrIsYxgGNE/TFKWU2LZ90MxwvVwvBEFAXdd4nodSis8dQwTI6XTGsiz6vufb3ABd1+G6Lnme4/v+f9E8zziOQ1mWAFIUxbP+KYqiyHCP49gQPb8nIrIsi4Rh+IokSRJp25Y3+OrQNM3XGz7zDsbcHXO0jDwtAAAAAElFTkSuQmCC");
_images.Add(_imageTypes.ShowAllColumns, "data:;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAfCAIAAAB/DupQAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAYdSURBVEhLtZXrb5NlGMb3/6AQjXzigyQaEwwGDDGixGDYQEUSFUWDcnACE7fhtq4HtpX2LV27Hmi7Q0e3MTbWLJtkAyY4NybqGId1Ze16Prynet3P87Yj+4zNnSZ7CL9cua7rvltl6F3FtPastgSeNfmjjd7oL+6Vc85Irf3pKeHJccvjDXOs/dFXpodH9Iuftvxb8+s/Hzf8/dH5Bx/U/fX+2YX3frq/p3b+3dPzu07N5fP5KkDnnpZmn5TuPS79vlS6s1gKz6vfdjyaWFDHF9TwnDZX76h7zy7gz7E5dXRWHflDvXZX8U4qeAzeUnqmlCuTsmdS6gxL9QHxtcN3VlZWquo90ZnFUrH8uRCIXexPfK5bxP+sPOr6UqZQZucPf4JSeTznSTb4s3g0D0uVx1p3+hshtblmemlpqerHy8uhGaXrRgz/XOdaPnE5VudN7K9/0ODPHOuI4PFMV+yQfvXrS4ntR++2hsQ6VxSP31mj+5sTB1rTeDzhyFc3LeOxORDbfSb61umVTQemCH1Yt/Thzw/21C7sOnn/nRPzO47PvXls9vWj97Z9cRffWw/PbJhXP7m95dDtLQdvbT546+Wa6ZeqtdlUPQViZQh92TdaYh+VDz6KOj49pyglWVElWZFkVaRRwlOzRUkpiHKhqOQLSq4o5wryyMRMNi9n8lI6J6eyUiorJjPS7urvCS103+BUVRtVUdTuoZv4BpQPuKKk+EITBVHJg8ugmGxBdnaPMq6UJq6UzIqJjLR9zxFC2wOjjMvlEhdi/QMT+JbBlTDEhV5PMAwo0FxvtiBl8nKnfyiTk1JskkBnpERG3LqjWjOE+UADLke7e0fJCknlUBpRcfiHCQ29RRkmkA85yeruh1ioJm6WuIl0GW29cj18czYw9Jt/YNIXGvcEx5yBYbs3hBffwIS3f9zdN+bsvt7pGxRcQXcw7OodcwTw55DgCVmcfe32gM03LHiHrJ5BiztkdoX0Qq+m2ua5piolhSSTahYdeU3RwQqR9DKLZRhCVkAvWSFlcjLE2rxDZYvhsriWxhQ1tMU7zLjMinJu0As0oGUuoZ29I2QxoGQFcdNZ0erqT2aoFWucmyrGU2VDzF2DG7iwGAK5v6SXtQJ6kRgqwarGuIguK5kdfUDDXwygmFiyrJqjyQfeYhYdEmMVrlRNyRYUCGQ+sAozbiojmmx+QLkPcUhOPoduc4bGbt57LrGRTt+AdT2xEbt/yOYZQGId9gDF5UZ6wQ5Hb5stYBK8BovbZO822gIGwa+z+HRmT4PRpXlt6grJClZO4XtRlFTodfeFC5UKs6pBr+AZYJLZamRYhdOiSQiQ3nQxlqJZTdJo6HZHqMLlLYYPnagw3MA2o8W8EjnJ7AxyH4jLKgwf9BYP+cu4cBncZ4ky+qK9n1YZFovrlRA8/XyVMeQvVjkvocJsNagPiI75K7Z0uGBxRS+46+hWR5+2dbxqRVINW2nleB+oZ1QJo8Wd4j6gEmhbClUTm9vsQHMfVpMFQq8VNEP0wtX/K8ZWoYf3F9eSXzUMYtzQX1iMGHmF4UOctRg+IEbuL9NbjK4VMJrqJmtgw9bBX8TIVk7rA48OMSbSUnnlEBpVGDFqaMZdYaOhm81XSDLpRR+oEtCLGLWVY1cYA38RI4+O58b7gBhh7rMEieXoSLyCvuRjXHYtGReDGEkyv+48tzTFqHGZXsotUUSM0QT0Mslx4kZiZTQaMhiedtAhHRTc/WZHb7vgM5qdVveAxYWt626z+U1Wr8Hs1Ld3GgW/weLVm926dmdLm6PZZG82CheMjkZjZ4PBXm+w1ettPzUJ6w3hP0jl604W2zyD7FRSf/lVQ27gxtj14XqRG5ReMHZWfFiJ5yF5eV210AOLUWG2GtRfumfOoLYa2umha4nENIsTrL/wN1FoNNgourIVMGQ5ll9vCK0GobVTSdshBKhnWtXoRMSTsNWprTJWo9yHep0ALtfLZ3m1jEZD+PXhP8y8D40GJ/ZNu5bsCgN9XmfjW4dKaLmtFc41WSPgxvPLTC+4z6Ev+Q4crdv72cm39325bWfNK2/seyFDv+i5XC4SiTx80R8w/wMqxePff8NAaAAAAABJRU5ErkJggg==");
}
private enum _imageTypes { SortAsc, SortAscActive, SortDesc, SortDescActive, HideColumn, ShowAllColumns }
private readonly Dictionary<_imageTypes, string> _images;
public new bool AllowSorting { get; set; }
public bool AllowHiding { get; set; }
public override object DataSource
{
get
{
return Page.Session[this.ID + ".DataSource"];
}
set
{
Page.Session[this.ID + ".DataSource"] = value;
base.DataSource = value;
}
}
private void AddCustomControlsRow()
{
if (DataSource != null)
{
if (AllowSorting || AllowHiding)
{
DataTable dataTable = GetDataTableFromDataSource();
if (dataTable.Columns.Count > 0 && dataTable.Rows.Count > 0)
{
if (this.HeaderRow != null && this.HeaderRow.Parent != null)
{
string sortExpression = dataTable.DefaultView.Sort.Replace(" ASC", "").Replace(" DESC", "");
SortDirection sortDirection = dataTable.DefaultView.Sort.EndsWith(" ASC") ? SortDirection.Ascending : SortDirection.Descending;
Table headerTable = (Table)this.HeaderRow.Parent;
GridViewRow controlRow = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
TableCell controlCell;
ImageButton imageButton;
foreach (TableCell cell in this.HeaderRow.Cells)
{
// Sicherstellen, dass es nicht die Spalte mit den Bearbeiten-Buttons ist, welche keine Überschrift enthält.
if (!(cell.Text.Replace(" ", "").Trim().Length > 0))
{
controlCell = new TableCell();
cell.Attributes.Add("style", "border-bottom: 0");
controlCell.Attributes.Add("style", "border-top: 0; text-align: center");
controlRow.Cells.Add(controlCell);
}
else
{
controlCell = new TableCell();
cell.Attributes.Add("style", "border-bottom: 0");
controlCell.Attributes.Add("style", "border-top: 0; text-align: center");
if (AllowSorting)
{
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(SortColumnAscButton_Click);
if (sortExpression == cell.Text && sortDirection == SortDirection.Ascending)
imageButton.ImageUrl = _images[_imageTypes.SortAscActive];
else
imageButton.ImageUrl = _images[_imageTypes.SortAsc];
controlCell.Controls.Add(imageButton);
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(SortColumnDescButton_Click);
if (sortExpression == cell.Text && sortDirection == SortDirection.Descending)
imageButton.ImageUrl = _images[_imageTypes.SortDescActive];
else
imageButton.ImageUrl = _images[_imageTypes.SortDesc];
controlCell.Controls.Add(imageButton);
controlRow.Cells.Add(controlCell);
}
if (AllowHiding)
{
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(HideColumnButton_Click);
imageButton.ImageUrl = _images[_imageTypes.HideColumn];
controlCell.Controls.Add(imageButton);
controlRow.Cells.Add(controlCell);
}
}
}
headerTable.Rows.AddAt(1, controlRow);
}
}
}
}
}
public static DataTable GetDataTableFromIEnumerable(IEnumerable enumerable)
{
DataTable dataTable = new DataTable();
DataRow row;
PropertyInfo[] propertyInfos;
foreach (object obj in enumerable)
{
propertyInfos = obj.GetType().GetProperties();
if (dataTable.Columns.Count == 0)
foreach (PropertyInfo pi in propertyInfos)
dataTable.Columns.Add(pi.Name, pi.PropertyType);
row = dataTable.NewRow();
foreach (PropertyInfo pi in propertyInfos)
{
object value = pi.GetValue(obj, null);
row[pi.Name] = value;
}
dataTable.Rows.Add(row);
}
return dataTable;
}
private DataTable GetDataTableFromDataSource()
{
DataTable dataTable;
if (DataSource is DataTable)
dataTable = (DataTable)DataSource;
else if (DataSource is IEnumerable)
dataTable = GetDataTableFromIEnumerable((IEnumerable)DataSource);
else
throw new NotSupportedException("Typ wird nicht unterstützt.");
return dataTable;
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{
// Weg der funktionierte, jedoch mit Editing Probleme macht: OnLoad: DataBind() / OnDataBound: AddCustomControls.
// Das DataBinding überschrieb die geänderten Werte wieder.
base.OnLoad(e);
}
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
}
protected override void OnDataBound(EventArgs e)
{
base.OnDataBound(e);
}
protected override void OnPreRender(EventArgs e)
{
AddCustomControlsRow();
base.OnPreRender(e);
}
protected override void OnUnload(EventArgs e)
{
base.OnUnload(e);
}
protected void SortColumnAscButton_Click(object sender, ImageClickEventArgs e)
{
DataTable dataTable = GetDataTableFromDataSource();
dataTable.DefaultView.Sort = ((ImageButton)sender).Attributes["data-column-name"] + " ASC";
DataSource = dataTable;
DataBind();
}
protected void SortColumnDescButton_Click(object sender, ImageClickEventArgs e)
{
DataTable dataTable = GetDataTableFromDataSource();
dataTable.DefaultView.Sort = ((ImageButton)sender).Attributes["data-column-name"] + " DESC";
DataSource = dataTable;
DataBind();
}
protected void HideColumnButton_Click(object sender, ImageClickEventArgs e)
{
// todo: Improve. Backup zum resetten, etc.
DataTable dataTable = GetDataTableFromDataSource();
dataTable.Columns.Remove(((ImageButton)sender).Attributes["data-column-name"]);
DataSource = dataTable;
DataBind();
}
Moved it to OnRowCreated which is also fired on every PostBack of the life cycle:
protected override void OnRowCreated(GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
if (AllowSorting || AllowHiding)
AddHeaderControls(e.Row);
}
base.OnRowCreated(e);
}
It also fixed the behavior of the sort buttons etc. A click on a (sort) button did not trigger the event because the "binding" in the PreRender is too late to handle the event.
I also changed the AddHeaderControls method a bit, instead of adding a whole row, I add the controls to the cell itself, here is a snippet:
foreach (TableCell cell in row.Cells)
{
// Sicherstellen, dass es nicht die Spalte mit den Bearbeiten-Buttons ist, welche keine Überschrift enthält.
if (cell.Text.Replace("&nbsp;", string.Empty).Trim().Length > 0)
{
// Write the Header Text into the cell as a (Literal)Control, because it would be lost otherwise.
cell.Controls.Add(new LiteralControl(cell.Text));
cell.Controls.Add(new LiteralControl("<br />"));
if (AllowSorting)
{
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(SortColumnAscButton_Click);
if (sortExpression == cell.Text && sortDirection == SortDirection.Ascending)
imageButton.ImageUrl = _images[_imageTypes.SortAscActive];
else
imageButton.ImageUrl = _images[_imageTypes.SortAsc];
cell.Controls.Add(imageButton);
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(SortColumnDescButton_Click);
if (sortExpression == cell.Text && sortDirection == SortDirection.Descending)
imageButton.ImageUrl = _images[_imageTypes.SortDescActive];
else
imageButton.ImageUrl = _images[_imageTypes.SortDesc];
cell.Controls.Add(imageButton);
}
if (AllowHiding)
{
imageButton = new ImageButton();
imageButton.Attributes.Add("data-column-name", cell.Text);
imageButton.Click += new ImageClickEventHandler(HideColumnButton_Click);
imageButton.ImageUrl = _images[_imageTypes.HideColumn];
cell.Controls.Add(imageButton);
}
}
}