2010-01-07 6 views
0

Je travaille depuis longtemps avec GridViews et DetailsViews, mais hier, j'ai rencontré un nouveau scénario, que je ne comprends pas du tout.DetailsView FindControl() retourne null après quelques postbacks

J'ai un GridView avec ImageButton (CommandName = "Insert") qui va changer le mode de DetailsView à insérer. Ensuite, je vais chercher un DropDownList à l'intérieur de cette DetailsView et ajouter des éléments de manière dynamique. Fonctionne bien, mais un premier la première fois que je presse ce ImageButton. Si je clique sur "Annuler" dans le DetailsView et appuie à nouveau sur ImageButton, la méthode .FindControl() renvoie null. Quel problème de cycle de vie suis-je confronté ici?

J'ai créé cet exemple: (Pour le faire fonctionner dans votre Visual Studio, lier juste un DataSource à l'DetailsView, sinon il ne sera pas rendu)

Markup:

<asp:GridView ID="gvCategory" runat="server" OnRowCommand="gvCategory_RowCommand"> 
    <Columns> 
    </Columns> 
    <EmptyDataTemplate> 
     <asp:ImageButton ImageUrl="~/images/add.png" ID="ibAdd" runat="server" CommandName="Insert" /> 
    </EmptyDataTemplate> 
    </asp:GridView> 
    <asp:DetailsView ID="dvCategory" runat="server" Width="150px" AutoGenerateRows="false" 
      AutoGenerateInsertButton="True" DataSourceID="LinqDataSource1"> 
    <Fields> 
     <asp:TemplateField HeaderText="foo"> 
      <InsertItemTemplate> 
       <asp:DropDownList ID="ddlCategory" runat="server" Width="150"></asp:DropDownList> 
      </InsertItemTemplate> 
     </asp:TemplateField> 
    </Fields> 
    </asp:DetailsView><asp:LinqDataSource ID="LinqDataSource1" runat="server" 
    ContextTypeName="WebApplication1.DataClasses1DataContext" 
    TableName="Categories"></asp:LinqDataSource> 

Codebehind :

protected void Page_Load(object sender, EventArgs e) 
    { 
     if (!Page.IsPostBack) 
     { 
      this.gvCategory.DataBind(); 
     } 

    } 

    protected void gvCategory_RowCommand(object sender, GridViewCommandEventArgs e) 
    { 
     if (e.CommandName == "Insert") 
     { 
      this.dvCategory.ChangeMode(DetailsViewMode.Insert); 
      DropDownList _ddlCat = (DropDownList)this.dvCategory.FindControl("ddlCategory"); 
      if (_ddlCat != null) 
      { 
       _ddlCat.Items.Clear(); 
       _ddlCat.Items.Add(new ListItem() { Text = "-- empty --", Value = "-1" }); 
      } 
     } 
    } 

J'ai aussi essayé d'utiliser un ItemTemplate, et non un InsertItemTemplate, mais cela se traduit par le même. Après avoir utilisé la méthode ChangeMode, DetailsView.CurrentMode == InsertMode. La seule chose que je peux penser est, que le balisage est déjà généré pour le ItemTemplate et changer le Mode en InsertMode ne peut pas affecter le balisage rendu, ou quelque chose comme ça.

Quelqu'un at-il une solution à ce problème? =)

Répondre

2

Je pense que vous êtes sur la bonne voie. Il est difficile de le savoir sans voir tout le code, mais en principe, chaque fois que vous changez le mode de rendu d'une ligne dans un contrôle de type répéteur, vous devez le relier pour le rendre à nouveau. Le fait que FindControl renvoie NULL ne signifie qu'une chose: LE CONTRÔLE N'EST PAS LÀ. Ce qui signifie qu'il n'a pas été rendu. Vous pouvez vérifier cela en regardant la hiérarchie de contrôle. Donc, dans votre gestionnaire pour Annuler, relivez-vous?

+0

Le code que j'ai posté ci-dessus est suffisant pour reproduire la situation décrite. Je vais essayer de voir si un autre .DataBinds() pourrait fonctionner. – citronas

+1

Un explicit dvCategory.DataBind() après avoir changé le mode apporté la solution. Merci homme, vous ne savez pas combien de temps j'ai travaillé sur ce;) Avez-vous, par hasard, savoir ce que l'appel .DataBind() fait exactement? Pourquoi ça marche? Force-t-il DetailsView à générer un nouveau balisage? – citronas

+0

Eh bien, maintenant vous posez les questions difficiles ... Honnêtement, pas tout à fait sûr, mais voici ma prise: Je ne pense pas de balisage est rendu, mais cet appel est ce qui déclenche la création de la hiérarchie de contrôle réelle. Et pour les contrôles basés sur des modèles, un seul modèle à la fois est créé: vous avez le ItemTemplate ou le EditTemplate, mais pas les deux. Alors pourquoi ça marche le premier appel ??? Pas certain. – Bryan

Questions connexes