web-dev-qa-db-fra.com

Contrôles et publication créés dynamiquement par ASP.NET

Je sais que cette question a été posée des milliers de fois, et je me suis déjà battue avec elle auparavant, mais pour une raison quelconque, je ne peux pas accomplir ce que je veux accomplir ... J'ai un LinkButton ajouté dynamiquement qui, lorsqu'il est cliqué, sera ajouté dynamiquement un contrôle (dans cet exemple, une zone de texte) sur le même panneau. L’intention est d’ajouter en permanence autant de contrôles que de fois où le LinkButton a été cliqué (c’est-à-dire que je clique dessus une fois, une case, puis un autre clic me donnera deux cases, un autre clic en ajoute une troisième). Dans le code ci-dessous, j'utilise la date et l'heure en cours sérialisées pour créer un identifiant unique pour chaque contrôle de zone de texte.

Lorsque j'exécute le code, un clic sur "Ajouter un filtre" générera un nouveau champ de texte, mais une nouvelle fois, un nouveau clic en créera un nouveau et éliminera celui qui le précède. Au lieu de cela, je veux conserver la zone de texte précédente ainsi que toutes les données qui y sont soumises.

Votre aide est appréciée.

Dans l'aspx:

<asp:Panel ID="pnlFilter" runat="server">

</asp:Panel>

Dans le aspx.cs:

protected void Page_Init(object sender, EventArgs e)
{
        LinkButton lb = new LinkButton();
        lb.ID = "lbAddFilter";
        pnlFilter.Controls.Add(lb);
        lb.Text = "Add Filter";
        lb.Click += new EventHandler(lbAddFilter_Click);
}


void lbAddFilter_Click(object sender, EventArgs e)
{
    TextBox tb = new TextBox();
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
    pnlFilter.Controls.Add(tb);
}
15
Honus Wagner

Pour ceux qui essaient de faire quelque chose comme ça: ne le fais pas. Pensez plutôt au flux d’informations et comprenez qu’il existe un meilleur moyen de le faire. Le ou les contrôles d'entrée n'ont pas besoin d'être créés dynamiquement. Elles peuvent être statiques et, une fois remplies et soumises, ces informations doivent aller quelque part (base de données, cache, session, par exemple). Une fois là-bas, à la publication, parcourez tous les éléments de votre stockage de choix et créez un affichage pour eux.

C’est ce que j’ai fait et cela a rendu la vie beaucoup plus facile. J'espère que ça aide quelqu'un.

16
Honus Wagner
void lbAddFilter_Click(object sender, EventArgs e)
{
    TextBox tb = new TextBox();
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
    pnlFilter.Controls.Add(tb);
}

Cela ne fonctionnera pas - c'est une question de cycle de vie, comme vous l'avez inférée dans votre question. Vous pouvez travailler avec cela de nombreuses façons, mais la suggestion de Honus Wagner est la plus flexible.

Ce qui se passe ici, c’est que vous appelez Controls.Add dans le gestionnaire d’événements et que le contrôle est ajouté à la liste de contrôle, et lors de la prochaine requête (qu’il s’agisse d’une publication partielle, d’une publication complète ou d’un nouvel accès à la page), ce contrôle est parti parce que vous ne l'avez pas persisté nulle part.

Voici ce qui se passe actuellement dans le cycle de vie de votre événement de page:

  1. Page appelle OnInit et ajoute votre LinkButton
  2. L'utilisateur clique sur le LinkButton
  3. La page appelle OnInit pour commencer la demande de publication. Le LinkButton est recréé
  4. Le gestionnaire d'événements est appelé, ce qui crée dynamiquement votre zone de texte et l'ajoute à la collection de contrôles.
  5. L'utilisateur clique à nouveau sur le LinkButton
  6. Page appelle OnInit pour ajouter le LinkButton à nouveau. La collection pnlFilter.Controls est vide à ce stade, à l'exception des éléments que vous avez déclarés de manière statique dans votre balisage.
  7. Le gestionnaire d'événement est appelé et une nouvelle zone de texte est ajoutée à la liste de contrôle.

Je ne suis pas sûr que ce soit la meilleure pratique, mais j'ai eu du succès avec un modèle similaire à celui-ci (notez que je n'ai pas testé ce code - il faudra peut-être l'ajuster):

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);

    LinkButton lb = new LinkButton();
    lb.ID = "lbAddFilter";
    pnlFilter.Controls.Add(lb);
    lb.Text = "Add Filter";
    lb.Click += new EventHandler(lbAddFilter_Click);

    // regenerate dynamically created controls
    foreach ( var control in PersistedControls )
    {
        pnlFilter.Controls.Add(GenerateControl(control));
    }
}

private IList<Control> _persistedControls;
private const string PersistedControlsSessionKey = "thispage_persistedcontrols";
private IList<Control> PersistedControls
{
    if (_persistedControls == null)
    {
        if (Session[PersistedControlsSessionKey] == null)
            Session[PersistedControlsSessionKey] = new List<Control>();
        _persistedControls = Session[PersistedControlsSessionKey] as IList<Control>;
    }
    return _persistedControls;
}    

void lbAddFilter_Click(object sender, EventArgs e)
{
    TextBox tb = new TextBox();
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
    PersistedControls.Add(tb);
    pnlFilter.Controls.Add(tb);
}

Notez que je ne suis pas sûr d'ajouter des objets de contrôle dans le magasin de session. Je crois que les ID de contrôle posent des problèmes susceptibles de générer des erreurs lors de la publication (un contrôle n'est peut-être pas sérialisable?). Dans la solution que j'ai développée, j'ai généré une nouvelle TextBox/Label/ComboBox/etc dans mon équivalent de la méthode GenerateControl et stocké une classe de conteneur personnalisée dans la collection PersistedControls qui contenait les différentes propriétés du contrôle d'interface utilisateur que je devais générer. sur chaque page Init.

11
Stefan Mohr

Je crois que vous aurez besoin de recréer chaque contrôle sur chaque publication.

Je sais que le contrôle Repeater stocke suffisamment d'informations sur ses enfants pour les recréer lorsque le databound est effectué ... Vous pourrez peut-être l'utiliser pour économiser un peu de travail.

1
AaronSieb

Essayez d'ajouter, 

if(!Page.IsPostback)
  --- your code that adds different controls.
0
Rahul Soni