0

So I have some code that dynamically creates an ASP.NET form based on an XML input file. I'm trying to add attributes to the controls at run time and I'm having some weird issues with list items.

My Server Side Code looks something like this:

Me.radioButtonList = New RadioButtonList()
Me.dropDownList = New DropDownList()
Me.listControl = Nothing
If controlType = "dropdown" Then
    Me.listControl = Me.dropDownList
Else
    Me.listControl = Me.radioButtonList
End If
For Each ansElement As Answer In strAnswers
    Dim newListItem = New ListItem(ansElement.AnswerText, ansElement.AnswerText)
    If ansElement.ActionID IsNot Nothing AndAlso ansElement.ActionID <> "" Then
        newListItem.Attributes.Add("actionID", ansElement.ActionID)
    End If
    Me.listControl.Items.Add(newListItem)
Next
Me.listControl.ID = controlID
Me.Controls.Add(Me.listControl)

The problem is when I run the code and the page is render the attributes are being added to the proceeding span tag of the control not the input item itself. So the rendered HTML ends up looking like this.

<span actionID="1">
    <input id="lst_dynamic_MedIllnesses_0" name="ctl00$MainContentPlaceHolder$FormGenerator1$lst_dynamic_MedIllnesses$lst_dynamic_MedIllnesses_0" value="None" type="checkbox">
    <label for="lst_dynamic_MedIllnesses_0">None</label>
</span>

What do I have to do to get the actionID attribute to be added to the actual input control and not the span tag?

Thanks!

1 Answer 1

4

I suppose you are talking about RadioButtonList. The problem with it is that it uses RadioButton control, and it has 3 attributes properties - Attributes, InputAttributes and LabelAttributes. Each of them is used for specific html element.

The problem with RadioButtonList, is that it uses just Attributes property, and doesn't use InputAttributes. Here is code of RadioButtonList.RenderItem method:

protected virtual void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
{
  if (repeatIndex == 0)
  {
    this._cachedIsEnabled = this.IsEnabled;
    this._cachedRegisterEnabled = this.Page != null && !this.SaveSelectedIndicesViewState;
  }
  RadioButton controlToRepeat = this.ControlToRepeat;
  int index1 = repeatIndex + this._offset;
  ListItem listItem = this.Items[index1];
  controlToRepeat.Attributes.Clear();
  if (listItem.HasAttributes)
  {
    foreach (string index2 in (IEnumerable) listItem.Attributes.Keys)
      controlToRepeat.Attributes[index2] = listItem.Attributes[index2];
  }
  if (!string.IsNullOrEmpty(controlToRepeat.CssClass))
    controlToRepeat.CssClass = "";
  ListControl.SetControlToRepeatID((Control) this, (Control) controlToRepeat, index1);
  controlToRepeat.Text = listItem.Text;
  controlToRepeat.Attributes["value"] = listItem.Value;
  controlToRepeat.Checked = listItem.Selected;
  controlToRepeat.Enabled = this._cachedIsEnabled && listItem.Enabled;
  controlToRepeat.TextAlign = this.TextAlign;
  controlToRepeat.RenderControl(writer);
  if (!controlToRepeat.Enabled || !this._cachedRegisterEnabled || this.Page == null)
    return;
  this.Page.RegisterEnabledControl((Control) controlToRepeat);
}

controlToRepeat is that RadioButton, and it specifies only Attributes property and ignores InputAttributes.

I can suggest way to fix it - you can create new class that inherits RadioButtonList, and use it instead of default. Here is code of that class:

public class MyRadioButtonList : RadioButtonList
{
    private bool isFirstItem = true;

    protected override void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
    {
        if (isFirstItem)
        {
            // this.ControlToRepeat will be created during this first call, and then it will be placed into Controls[0], so  we can get it from here and update for each item.
            var writerStub = new HtmlTextWriter(new StringWriter());
            base.RenderItem(itemType, repeatIndex, repeatInfo, writerStub);
            isFirstItem = false;
        }

        var radioButton = this.Controls[0] as RadioButton;

        radioButton.InputAttributes.Clear();
        var item = Items[repeatIndex];
        foreach (string attribute in item.Attributes.Keys)
        {
            radioButton.InputAttributes.Add(attribute, item.Attributes[attribute]);                
        }
        // if you want to clear attributes for top element, in that case it's a span, then you need to call
        item.Attributes.Clear();

        base.RenderItem(itemType, repeatIndex, repeatInfo, writer);

    }
}

A bit of description - it has isFirstItem property, as RadioButton control that used by it is created in runtime in the first access, so we need to call RenderItem before we can update InputAttrubutes property. So we call it once and send some stub HtmlTextWriter, so it won't be displayed twice. And then after that we just get this control as Controls[0], and for each ListItem we update InputAttributes values.

PS. Sorry, I didn't use VB.Net so control is written in C#

Sign up to request clarification or add additional context in comments.

5 Comments

Does the CheckboxList item suffer from the same problem and would thus need overrode as well?
Also how do I prevent it from rendering the attribute in both places then? Now I'm getting the attributes on the span tag AND the input tag. So that's causing another set of issues.
Yes, CheckBoxList has the same problem. But instead of RadioButtonList that uses RadioButton control for item, CheckBoxList uses CheckBox control. And RadioButton inherits that CheckBox.
I updated code with sample how to remove attributes from span. Basically you just need to call item.Attributes.Clear(); after you copied them to InputAttributes.
Awesome this is working absolutely perfectly for me now! Great answers, thanks for all the help! It's odd to me that the RadioButtonList and CheckBoxList don't expose properties by default. Seems like something that would be needed a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.