2008-11-08 5 views
4

Je configure un contrôle utilisateur piloté par une configuration XML. Il est plus facile d'expliquer par l'exemple. Jetez un oeil à l'extrait de configuration suivante:Comment créer un contenu conditionnel dans une base de données Répéteur

<node> 
    <text lbl="Text:"/> 
    <checkbox lbl="Check me:" checked="true"/> 
</node> 

Ce que je suis en train de réaliser pour traduire cet extrait dans une seule zone de texte et un contrôle de case à cocher. Bien sûr, si l'extrait contenait plus de nœuds, plus de contrôles seraient générés automatiquement.

Donner le caractère itératif de la tâche, j'ai choisi d'utiliser le répéteur. A l'intérieur, j'ai placé deux contrôles (bien plus, voir ci-dessous), un CheckBox et un Editbox. Afin de choisir quel contrôle activer, j'ai utilisé une commande de commutateur inline, en vérifiant le nom du nœud de configuration actuel.

Malheureusement, cela ne fonctionne pas. Le problème réside dans le fait que le commutateur est en cours d'exécution pendant le temps de rendu, longtemps après que la liaison de données s'est produite. Cela seul ne serait pas un problème, n'était pas le fait qu'un nœud de configuration pourrait offrir les informations nécessaires à la liaison de données. Considérez ce qui se passerait si le contrôle de case à cocher essayait de se lier au nœud de texte dans l'extrait ci-dessus, cherchant désespérément son attribut "checked".

Des idées pour rendre cela possible?

Merci, Boaz

Voici mon code actuel:

Voici mon code (qui fonctionne sur une syntaxe plus complexe que celle ci-dessus):

<asp:Repeater ID="settingRepeater" runat="server"> 
     <ItemTemplate> 
      <% 
       switch (((XmlNode)Page.GetDataItem()).LocalName) 
       { 
       case "text": 
      %> 
      <asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" /> 
      <asp:TextBox ID="settingsLabelText" Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>' 
       runat="server" AutoPostBack="true" Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>' 
       /> 
      <% break; 
       case "checkbox": 
      %> 
      <asp:CheckBox ID="settingsCheckBox" Text='<%# XPath("@lbl") %>' runat="server" 
         Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>' 
      /> 
      <% break; 
       } %> 
      &nbsp;&nbsp; 
     </ItemTemplate> 
    </asp:Repeater> 

Répondre

4

Un week-end plus tard, voici ce que je suis venu avec une solution. Mon objectif principal était de trouver quelque chose qui fonctionnera et vous permettra de continuer à spécifier le contenu exact du modèle d'article dans le balisage. Faire des choses à partir du code fonctionnerait mais peut encore être lourd.

Le code devrait être simple à suivre, mais l'essentiel de la question se trouve en deux parties.

La première est l'utilisation de l'événement créé par Repeater pour filtrer les parties indésirables du modèle.

La seconde consiste à stocker les décisions prises dans ViewState afin de recréer la page lors de la publication. Ce dernier est crucial car vous remarquerez que j'ai utilisé Item.DataItem. Pendant les post-retours, la commande de contrôle se produit beaucoup plus tôt dans le cycle de vie de la page. Lorsque le ItemCreate se déclenche, le DataItem est null.

Voici ma solution:

balisage contrôle

<asp:Repeater ID="settingRepeater" runat="server" 
      onitemcreated="settingRepeater_ItemCreated" 
      > 
     <ItemTemplate> 
      <asp:PlaceHolder ID="text" runat="server"> 
        <asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" /> 
        <asp:TextBox ID="settingsLabelText" runat="server" 
         Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>' 
        Columns='<%# XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>' 

        /> 

      </asp:PlaceHolder> 
      <asp:PlaceHolder ID="att_adder" runat="server"> 
       <asp:CheckBox ID="settingsAttAdder" Text='<%# XPath("@lbl") %>' runat="server" 
          Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>' 
       /> 
      </asp:PlaceHolder> 
     </ItemTemplate> 
    </asp:Repeater> 

Note: pour la facilité supplémentaire que j'ajouté le contrôle PlaceHolder aux choses de groupe et de faire que la décision de contrôle pour éliminer plus facilement.

code derrière

Le soufflet de code est construit sur l'idée que chaque élément de répéteur est d'un type. Le type est extrait de la configuration xml. Dans mon scénario spécifique, je pourrais faire ce type à un seul contrôle au moyen de l'ID. Cela pourrait être facilement modifié si nécessaire.

protected List<string> repeaterItemTypes 
    { 
     get 
     { 
     List<string> ret = (List<string>)ViewState["repeaterItemTypes"]; 
     if (ret == null) 
     { 
      ret = new List<string>(); 
      ViewState["repeaterItemTypes"] = ret; 
     } 
     return ret; 
     } 
    } 

    protected void settingRepeater_ItemCreated(object sender, RepeaterItemEventArgs e) 
    { 
     string type; 
     if (e.Item.DataItem != null) 
     { 
     // data binding mode.. 
     type = ((XmlNode)e.Item.DataItem).LocalName; 
     int i = e.Item.ItemIndex; 
     if (i == repeaterItemTypes.Count) 
      repeaterItemTypes.Add(type); 
     else 
      repeaterItemTypes.Insert(e.Item.ItemIndex, type); 
     } 
     else 
     { 
     // restoring from ViewState 
     type = repeaterItemTypes[e.Item.ItemIndex]; 
     } 

     for (int i = e.Item.Controls.Count - 1; i >= 0; i--) 
     { 
     if (e.Item.Controls[i].ID != type) e.Item.Controls.RemoveAt(i); 
     } 
    } 
1

Vous avez besoin quelque chose cela ressemble plus à ceci:

<ItemTemplate> 
    <%# GetContent(Page.GetDataItem()) %> 
</ItemTemplate> 

Et puis tout vos contrôles générés dans le code-behind.

Questions connexes