2009-11-02 7 views
0

J'essaie de créer un contrôle personnalisé qui étend le RadComboBox de Telerik pour créer une liste déroulante Checkbox avec des modèles par défaut. Le plan est d'utiliser le contrôle dans plusieurs endroits, donc je voulais consolider toute la logique en un seul endroit.Contrôle du serveur ASP.NET basé sur RadComboBox - Problème de publication

Cependant, je rencontre un couple de problèmes étranges sur la publication. Si vous cochez quelques éléments, puis cliquez sur le bouton Appliquer, les éléments corrects sont sélectionnés, mais le texte de la case à cocher est différent. Puis, lors de la publication suivante, j'obtiens l'erreur Multiple controls with the same ID 'i2' were found. FindControl requires that controls have unique IDs.

Le contrôle personnalisé est joint. Toute aide est appréciée.

C# Code:

/// <summary> 
/// Private Header template class for the DropdownCheckboxList 
/// </summary> 
class CheckboxListFooterTemplate : ITemplate 
{ 
    #region Public Methods 

    public void InstantiateIn(Control container) 
    { 
     string footer = "<input type=\"submit\" value=\"Apply\" />"; 
     container.Controls.Add(new LiteralControl(footer)); 
    } 

    #endregion Public Methods 
} 

/// <summary> 
/// Private Header template class for the DropdownCheckboxList 
/// </summary> 
class CheckboxListHeaderTemplate : ITemplate 
{ 
    #region Public Methods 

    public void InstantiateIn(Control container) 
    { 
     string header = "<input type=\"button\" value=\"Check All\" onclick=\"CheckAll(&quot;{0}&quot;, true)\" />"; 
     header += "&nbsp;<input type=\"button\" value=\"Uncheck All\" onclick=\"CheckAll(&quot;{0}&quot;, false)\" />"; 

     container.Controls.Add(new LiteralControl(string.Format(header, container.Parent.ClientID))); 
    } 

    #endregion Public Methods 
} 

/// <summary> 
/// Template class for the DropdownChecklistBox 
/// </summary> 
class CheckboxListTemplate : ITemplate 
{ 
    #region Constants 

    //this div will stop the list from closing as a listitem is clicked 
    const string head = "<div onclick=\"StopPropagation(event)\" class=\"combo-item-template\">"; 
    const string tail = "</div>"; 

    #endregion Constants 

    #region Private Methods 

    /// <summary> 
    /// Bind the data to the checkbox 
    /// </summary> 
    /// <param name="sender">Checkbox to bind data to</param> 
    /// <param name="e"></param> 
    private void checkbox_DataBinding(object sender, EventArgs e) 
    { 
     CheckBox target = (CheckBox)sender; 
     RadComboBoxItem item = (RadComboBoxItem)target.BindingContainer; 
     string itemText = (string)DataBinder.Eval(item, "Text"); 
     target.Text = itemText; 
    } 

    #endregion Private Methods 

    #region Public Methods 

    /// <summary> 
    /// Create the checkbox list items in the template 
    /// </summary> 
    /// <param name="container">Container that the control will be added</param> 
    public void InstantiateIn(Control container) 
    { 
     CheckBox checkbox = new CheckBox(); 
     checkbox.ID = "chkList"; 
     checkbox.Attributes.Add("onclick", string.Format("onCheckBoxClick(this, \"{0}\")", container.Parent.ClientID)); 

     container.Controls.Add(new LiteralControl(head)); 
     checkbox.DataBinding += new EventHandler(checkbox_DataBinding); 
     container.Controls.Add(checkbox); 

     container.Controls.Add(new LiteralControl(tail)); 
    } 

    #endregion Public Methods 
} 

//todo: complete summary 
/// <summary> 
/// based on telerik demo: http://demos.telerik.com/aspnet-ajax/combobox/examples/functionality/templates/defaultcs.aspx 
/// </summary> 
[DefaultProperty("Text")] 
[ToolboxData("<{0}:DropdownCheckboxList runat=server></{0}:DropdownCheckboxList>")] 
public class DropdownCheckboxList : RadComboBox, INamingContainer 
{ 
    #region Private Properties 

    string SelectedText 
    { 
     get 
     { 
      StringBuilder values = new StringBuilder(SelectedItems.Count); 
      foreach (RadComboBoxItem item in SelectedItems) 
       values.Append(item.Text + ", "); 

      if (values.Length > 0) 
       return values.ToString().Remove(values.Length - 2, 2); 
      else 
       return EmptyMessage; 
     } 
    } 

    #endregion Private Properties 

    #region Public Properties 

    public RadComboBoxItemCollection SelectedItems 
    { 
     get 
     { 
      CheckBox chk = null; 
      RadComboBoxItemCollection selectedItems = new RadComboBoxItemCollection(this); 

      foreach (RadComboBoxItem item in Items) 
      { 
       chk = (CheckBox)item.FindControl("chkList"); 
       if (chk != null && chk.Checked) 
        selectedItems.Add(item); 
      } 

      return selectedItems; 
     } 
    } 

    //todo: summary 
    public override string SelectedValue 
    { 
     get 
     { 
      StringBuilder values = new StringBuilder(SelectedItems.Count); 
      foreach (RadComboBoxItem item in SelectedItems) 
       values.Append(item.Value + ", "); 

      if (values.Length > 0) 
       return values.ToString().Remove(values.Length - 2, 2); 
      else 
       return ""; 
     } 
     set 
     { 
      if (value != null) 
       SelectedValues = new List<string>(value.Split(',')); 
     } 
    } 

    //todo: summary 
    public List<string> SelectedValues 
    { 
     get 
     { 
      List<string> selectedValues = new List<string>(); 

      foreach (RadComboBoxItem item in SelectedItems) 
      { 
       selectedValues.Add(item.Value); 
      } 

      return selectedValues; 
     } 
     set 
     { 
      RadComboBoxItem item = null; 
      CheckBox chk = null; 

      foreach (string val in value) 
      { 
       item = Items.FindItemByValue(val.Trim()); 

       if (item != null) 
       { 
        chk = (CheckBox)item.FindControl("chkList"); 

        if (chk != null) 
         chk.Checked = true; 
       } 
      } 
     } 
    } 

    #endregion Public Properties 

    #region Protected Methods 

    protected override void CreateChildControls() 
    { 
     if (base.HeaderTemplate == null) 
      base.HeaderTemplate = new CheckboxListHeaderTemplate(); 

     if (base.ItemTemplate == null) 
      base.ItemTemplate = new CheckboxListTemplate(); 

     if (base.FooterTemplate == null) 
      base.FooterTemplate = new CheckboxListFooterTemplate(); 

     base.CreateChildControls(); 
    } 

    protected override void OnPreRender(EventArgs e) 
    { 
     base.OnPreRender(e); 
     string resourceName = "CustomControls.DropdownCheckboxList.js"; 

     ClientScriptManager cs = this.Page.ClientScript; 
     cs.RegisterClientScriptResource(typeof(CustomControls.DropdownCheckboxList), resourceName); 

     Text = SelectedText; 
    } 

    #endregion Protected Methods 
} 

code Javascript:

//based on telerik demo: http://demos.telerik.com/aspnet-ajax/combobox/examples/functionality/templates/defaultcs.aspx 

    var cancelDropDownClosing = false; 

    function StopPropagation(e) { 
     //cancel bubbling 
     e.cancelBubble = true; 
     if (e.stopPropagation) { 
      e.stopPropagation(); 
     } 
    } 

    function onDropDownClosing() { 
     cancelDropDownClosing = false; 
    } 

    function CheckAll(comboBoxId, value) { 
     var combo = $find(comboBoxId); 

     //get the collection of all items 
     var items = combo.get_items(); 

     //enumerate all items 
     for (var i = 0; i < items.get_count(); i++) { 
      var item = items.getItem(i); 
      //get the checkbox element of the current item 
      var chk1 = $get(combo.get_id() + "_i" + i + "_chkList"); 
      chk1.checked = value; 
     } 
    } 

    function onCheckBoxClick(chk, comboBoxId) { 
     var combo = $find(comboBoxId); 
     //holds the text of all checked items 
     var text = ""; 
     //holds the values of all checked items 
     var values = ""; 
     //get the collection of all items 
     var items = combo.get_items(); 
     //enumerate all items 
     for (var i = 0; i < items.get_count(); i++) { 
      var item = items.getItem(i); 
      //get the checkbox element of the current item 
      var chk1 = $get(combo.get_id() + "_i" + i + "_chkList"); 
      if (chk1.checked) { 
       text += item.get_text() + ", "; 
       values += item.get_value() + ", "; 
      } 
     } 
     //remove the last comma from the string 
     text = removeLastComma(text); 
     values = removeLastComma(values); 

     if (text.length > 0) { 
      //set the text of the combobox 
      combo.set_text(text); 
     } 
     else { 
      //all checkboxes are unchecked 
      //so reset the controls 
      combo.set_text(""); 
     } 
    } 

    //this method removes the ending comma from a string 
    function removeLastComma(str) { 
     return str.replace(/,$/, ""); 
    } 

Répondre

0

Cette ligne InstantiateIn(Control container) est la principale cause du problème:

checkbox.ID = "chkList";

Cette ligne fait chaque case à cocher ont le même id - ils devraient être uniques.

Il pourrait ressembler davantage à ce

checkbox.ID = Container.ID + SomeUniqueString;

J'ai créé un projet avec le code que vous avez fourni et j'ai dupliqué l'erreur avec un seul contrôle sur la page. (il y avait aussi d'autres erreurs dans le javascript, mais j'ai été capable de les ignorer.)

Je ne vois pas de moyen facile de créer les identifiants uniques afin que vous sachiez ce qu'ils devaient faire la recherche. Ainsi, au lieu de cela:

chk = (CheckBox)item.FindControl("chkList"); 

J'ai essayé ceci:

foreach (var o in item.Controls) 
{ 
    if (o is CheckBox) 
    { 
     chk = (CheckBox) o; 
    } 
} 

Il a éliminé l'erreur et m'a permis de sélectionner plus d'un élément. Cependant, ce code n'est pas idéal - il suppose qu'il n'y a qu'une seule case à cocher. Vous feriez mieux de vous assurer que les identifiants sont uniques. L'approche que je prendrais serait de baser l'ID sur la valeur de l'élément de zone de liste déroulante.

Si les éléments sélectionnables sont fixes (l'utilisateur ne peut pas ajouter de nouveaux éléments via la zone de liste déroulante), vous pouvez essayer d'utiliser un RadMenu à la place. Nous avons un contrôle très similaire, mais nous utilisons RadMenu. Nous définissons simplement l'image sur l'élément de menu pour indiquer l'état de la sélection, et nous gardons la trace des éléments sélectionnés sous notre contrôle.

Questions connexes