我正在尝试创建一个自定义控件,从Telerik扩展RadComboBox以使用默认模板创建下拉复选框列表。计划是在几个地方使用控件,所以我想在一个地方合并所有逻辑。
然而,我在回发时遇到了一些奇怪的问题。如果您检查了几个项目然后点击“应用”按钮,则会选择正确的项目,但复选框上的文本会有所不同。然后在下一个回发中我收到错误Multiple controls with the same ID 'i2' were found. FindControl requires that controls have unique IDs.
附加是自定义控件。任何帮助表示赞赏。
C#代码:
/// <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("{0}", true)\" />";
header += " <input type=\"button\" value=\"Uncheck All\" onclick=\"CheckAll("{0}", 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
}
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(/,$/, "");
}
答案 0 :(得分:0)
InstantiateIn(Control container)
中的这一行是问题的主要原因:
checkbox.ID = "chkList";
这一行使每个复选框都具有相同的ID - 它们应该是唯一的。
所以看起来可能更像是
checkbox.ID = Container.ID + SomeUniqueString;
我使用您提供的代码创建了一个项目,并在页面上只有一个控件复制了错误。 (javascript中还有其他错误,但我能够忽略它们。)
我看不到创建唯一ID的简单方法,以便您可以知道他们要做什么。所以不要这样:
chk = (CheckBox)item.FindControl("chkList");
我试过了:
foreach (var o in item.Controls)
{
if (o is CheckBox)
{
chk = (CheckBox) o;
}
}
它消除了错误并允许我选择多个项目。但是,此代码并不理想 - 它假设只有一个复选框。你最好确保id是唯一的。我将采用的方法是将id基于组合框项的值。
如果修改了可选项(用户无法通过组合框添加新项),则可以尝试使用RadMenu。我们有一个非常类似的控件,但我们使用RadMenu。我们只需在菜单项上设置图像以指示选择状态,我们就会跟踪控制范围内的所选项目。