Controls ajoutés dynamiquement [Résolu]

Signaler
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005
-
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005
-
Bonjour,

if (!IsPostBack){
// cree les datagrid dynamiquement
CreerListeDemande();
// cree les panels contenant les datagrid
CreerPanelsDemande();
// ajoute les datagrid dans les panels et les panels dans la page
AjouterComposants();
// bind les datagrid aux donnees
BindListeDemande();

for (int i=0;i<villes.Length;i++){
// ajoute les composants dynamique au viewstate
ViewState.Add("grille_"+villes[i], grilles[i]);
ViewState.Add("panel_"+villes[i], panels[i]);
}
}

voila mon pb:
Je ne sais pas a l'avance combien de datagrid j'aurais a construire (idem pour les panels).
Donc j'arrive a les creer et les afficher, mais des que je clic sur un boutton (meme sans listener), je perd l'affichage des composants ajoute dynamiquement. Donc j'essaie de les mettre dans le ViewStateBag puisque c'est le viewstate qui ne fonctionne pas apparemment. Et ca m'evite de les mettre dans un variable de sission parcequ'ils risquent de predre de la place.
Le pb c'est pas la fonctin Add du StateBag me jete cette erreur :

The type 'System.Web.UI.WebControls.DataGrid' must be marked as Serializable or have a TypeConverter other than ReferenceConverter to be put in viewstate.

En plus l'utilisateur doit pouvoir agir sur les datagrid donc je peux pas les recreer a chaque aller-retour sinon les evenements de l'utilisateur sur les datagrid ne seront pas prises en compte (puisque c'est le viewstate qui permet de savoir quel element a change).
Que dois-je faire ?

12 réponses

Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

CA MARCHE !!!
En fait je suis parti de ta solution. Comme je ne connaissais pas la fonction que tu overridais, je l'ai cherchee sur le net et je suis tombe sur le cycle de vie d'une page ASP.NET. C'est la que g vu que le plus important etait que je cree mes controls juste avant que l'appli reccupere les informations de viewstate. La fonction la plus proche etant Page_init.
Donc g mis ma fonction de creation dynamique dans cette fonction (parceque dans la tienne j'etais pas sur d'avoir la SessionState).
Donc je conseil a tout le monde de connaitre par coeur le cycle de vie d'une page ASP.NET avant de programmer !!! y'en a un aprecu dans la MSDN : (http://msdn.microsoft.com/library/fre/default.asp?url=/library/FRE/cpguide/html/cpconcontrolexecutionlifecycle.asp)
mais elle est pas super complete. Mieux vaut chercher en anglais (life cycle of ASP.NET page) dans google.

En tout cas je te remercie beaucoup de ton aide et du temps que tu as passes sur mon probleme. Au bout de 2 semaines de galere, j'espere que des gens en profiteront!

Sam
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
25
L'erreur je peux te l'expliquer, la solution j'ai pas trop le temps d'y reflechir :-/



donc : le viewstate sert à sauvegarder des paramètres entre les pages,
pour cela asp.net a un dictionnaire qui s'appelle viewstate, quand il
génére la page, il va regarder le dico, puis va le serializer en base
64, puis le mettre dans le champ caché __viewstate (regarde la source
HTML de la page) pour qu'il puisse serializé il faut qu'il y a des
string & co or, un datagrid c'est un objet trés complexe ... par
contre tu peux serializer ton dataset (beurk)



Je vois pas vraiment de possibilité, la création de controle à la volée
c'est trés pénible pour les postbacks ... car il recharge le viewstate
aprés avoir instancié les controles :-/



Ce que tu pourrais eventuellement faire, j'ai jamais testé cette idée,
mais tu overrides le new de la page, tu declare tes datagrid



protected witheevents dg as datagrid



public sub new()

if page.ispostback

dg = new datagrid blabla



end sub


Je suis pas du tout sur que ca fonctionne, je viens d'avoir cette idée,
mais si j'ai rien oublié en théorie ca devrait fonctionner :p



Sinon sais tu le nombre maximum de datagrid que tu peux avoir ? moins de 10 ?




<hr>Cyril - MCP ASP.net
Webmaster de : Hoshimi.CodeS-SourceS.fr
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

la question est : a quel moment est appele le constructeur ?
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

Et en plus, pour initialiser les controls il faudrait que j'appelle le constructeur de la super class. Mais je sais pas comment on fait (en C#).
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
25
Le constructeur est la premiere chose qui est appellé dans une classe :D

en C#

public class toto : personne
{
void toto()
{

}
}

J'espere pas dire de betises car C# n'est pas mon fort :p


<HR>
Cyril - MCP ASP.net
Webmaster de : Hoshimi.CodeS-SourceS.fr
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

Bon... d'accord je suis pas tres bon mais de la a me dire que le constructeur est la premiere chose appelee dans une classe... :-/ lol
non mais pour un objet de type Page, il est appele a chaque appel de la page? Si oui du code dans le constructeur ou dans le Page_load c'est pareil. Non ?

Sinon la syntaxe du constructeur est la bonne mais ma question est plutot comment appeler le constructeur de la super classe dans le constructeur de ma classe fille ( en java c'est 'super()' ).
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
25
euh ... on appel pas un constructeur !!!

le constructeur est automatiquement appellé quand on instancie le control

Control ctrl = new ctrl();

mais la je vois pas pourquoi une classe fille ???? ce que je te dis c'est redefinir le new de ta page !

Public Class Tapage : System.Web.UI.Page
{

// la tu declares le datagrid
//Protected WithEvents ctrl() as Datagrid ' <== mettre ca en C#

void Tapage()
{

// ici tu peux l'ajouter

}

void page_load()
{
la t'en fait comme d'habitude
}

}

et le page_load est trés loin d'etre la premiere chose qui est appellé au sein de la classe, il y a beaucoup de choses avant, il y a meme des event : init ...

en mettant tes controles dans le constructeur de la classe tu vas faire à peu prés comme si tu les mettais dans la page.

En fait, lorsque tu fais ta requete, tu vas charger tapage.aspx, la il va regarder toutes tes balises runat=server puis va les charger dans la classe spécifié dans le header ...

donc les controles qui sont dans la page, sont chargé dans le new (je sais pas exactement dans quelle méthode, j'ai pas été regardé aussi profond) en instanciant les controles dans le new tu n'auras donc aucune difference, la seule chose qui pourrait t'emmerder c'est qu'il faut que tu aie une collection de datagrid, donc pour t'abonner aux events, ce sera un poil plus chiant.

Ce truc m'interresse donc des que j'ai le temps j'essaierais de faire ce que j'ai en tete.


<HR>
Cyril - MCP ASP.net
Webmaster de : Hoshimi.CodeS-SourceS.fr
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

je vais essayer ta solution. Elle me parait interessante et t'as raison, apparemment g pas besoin d'appeler le constructeur.
Mais juste pour clarifier le coup du constructeur je voudrais t'expliquer a quoi je pensais :
Public Class Tapage : System.Web.UI.Page
cette ligne denote bien que ma clase TaPage est une classe heirtee de la classe Page. Dans ce cas, si le constructeur de la super classe Page fait beaucoup de choses (comme instancier des objet dont je n'ai pas connaissance ou initialiser des variables, ...) alors quand je vais overrider le constructeur, tout cela ne sera plus fait (un override n'est pas un ajout mais un remplacement). Donc en Java (j'ai que cet exemple la en tete), dans le constructeur de la classe fille, on peut appeler le constructeur de la super classe (avec le mot clef super) afin de ne pas reecrire ce qu'il contenait. Sinon tout serait ecrase.
Je sais pas si j'ai ete clair :-/

Je te tien au courant si ta solution marche. En attendant, merci.
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

Bon je suis tombe sur un os. apparemment ca pourrait marcher ta solution mais g besoin de ma base de donnees pour creer les controles. Or, le pb c'est que ma connexion est dans la SessionState (parceque les utilisateurs n'attaquent pas tous la meme base de donnees). Or le SessionState n'est pas encore accessible dans le constructeur (a moins que le constructeur d'origine de la classe Page fasse une manoeuvre pour mettre le sessionstate a disposition). Ce qui me fais dire ca c'est cette erreur :

Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive

Donc apparement il faut mettre une variable a true mais ou (oui c deja mis dans la directive @page)? Mystere! lol
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
25
pour appeller le constructeur de la classe mere :

public sub new()
mybase.new()

end sub

j'avais pas compris la question :$ et c'est vrai que si tu le met pas, je sais pas si ca va marcher :p

pour l'erreur, tu n'auras accés absolument à rien ! meme pas un request.querystring :p (peut etre que si mais je pense pas)

si le nombre de datagrid est décidé dans la bdd :/ est surtout que la connectionstring est dans une variable session, je sais pas trop comment tu pourrais faire pour l'instant peut etre en faisant

httpcontext.current.qqchose.session ?

bon courage :p


<HR>
Cyril - MCP ASP.net
Webmaster de : Hoshimi.CodeS-SourceS.fr
Messages postés
20
Date d'inscription
lundi 16 mai 2005
Statut
Membre
Dernière intervention
29 juillet 2005

J'ai toujours pas de solution.
Donc si une autre idee de genie te vient à l'esprit, n'hesite pas parceque pour le moment je suis dans la merde.
En attendant merci de ton aide.

(P.S.: je posterai de tps en tps pour te rappeler ce sujet fort interessant ;) lol
Messages postés
6814
Date d'inscription
dimanche 15 décembre 2002
Statut
Modérateur
Dernière intervention
13 octobre 2010
25
J'ai regardé ca rapidement ce matin, mais comme le site plante a fond (et que Nix est pas la avant lundi donc faut prier pour que ca se retablisse tout seul :p) j'ai pas pu t'envoyer.

Voila ce que ca donnne


Imports System.Collections.Generic

Partial
Class AjoutDynamique

Inherits System.Web.UI.Page

Implements INamingContainer

Private textboxList
As
New List(
Of TextBox)

Private btnList
As
New List(
Of Button)

Protected
Overrides
Sub CreateChildControls()

For i
As
Integer = 0
To 10

Dim txtbox
As
New TextBox
txtbox.ID =
"txtbox" & i.ToString
ph1.Controls.Add(txtbox)
textboxList.Add(txtbox)

Dim btn
As
New Button
btn.ID =
"btn" & i.ToString
btn.Text =
"OK"
btn.CommandArgument = i.ToString

AddHandler btn.Click,
AddressOf btn_click

ph1.Controls.Add(btn)
btnList.Add(btn)

ph1.Controls.Add(
New LiteralControl(
"
"))

Next

MyBase.CreateChildControls()

End
Sub

Private
Sub btn_click(
ByVal sender
As
Object,
ByVal e
As EventArgs)

Dim btn
As Button =
CType(sender, Button)

lit1.Text =
String.Format(
"le bouton N° {0} a été clické, la valeur du textbox N° {0} est {1}", btn.CommandArgument, textboxList(btn.CommandArgument).Text)

End
Sub

End
Class

Vu que je bosse en .net2 je me suis pas privé d'utiliser les generics ;) si tu connais pas c'est le list(of textbox) ca permet de créer une collection d'objet typé trés rapidement, faudra done passer par un arraylist et caster :p

Ce qui a d'interressant c'est que je rajout les controles juste avant le loadviewstate c'est à dire avant la méthode qui va regarder le viewstate ... j'ai pas vérifié mais peut etre qu'ici t'as les variables sessions, sinon tu peux tenter un truc du genre :


HttpContext.Current.Session(
"truc")

en vérifiant bien sur que HttpContext.current <> nothing etc....

normalement le problème est résolu ? non ?

en tout cas c'est la seule maniere propre sans trop bidouille de rajouter des object dynamiquement :)


<HR>
Cyril - MCP ASP.net
Webmaster de : Hoshimi.CodeS-SourceS.fr