OnCheckedChanged Вложенные элементы управления списком

У меня есть следующий вложенный список...

<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
    <LayoutTemplate>
        <asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
    </LayoutTemplate>
    <ItemTemplate>
        <%# Eval("DESCRIPTION")%>
            <asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
                <LayoutTemplate>
                    <asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
                </LayoutTemplate>
                <ItemTemplate>
                    <asp:RadioButton ID="rdbSelect" runat="server" AutoPostBack="true" OnCheckedChanged="rdbSelectChanged"/>                                        
                        <%# Eval("Description")%>
                </ItemTemplate>
        </asp:ListView>
    </ItemTemplate>
</asp:ListView>

Я получаю радиокнопки OnCheckedChanged вот так...

Protected Sub rdbSelectChanged(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim rb1 As RadioButton = CType(sender, RadioButton)

    Dim lvwAnswers = DirectCast(lvwRiskQuestions.FindControl("lvwAnswers"), ListView)

    For Each row As ListViewItem In lvwAnswers.Items
        Dim rb As RadioButton = row.FindControl("rdbSelect")
        If rb IsNot Nothing AndAlso rb.Checked Then
            rb.Checked = False
        End If
    Next
    rb1.Checked = True
End Sub

У меня проблема в том, что «lvwAnswers» ничего не значит. Я предполагаю, что я неправильно делаю свой findcontrol.

Любая помощь очень ценится.


person Dooie    schedule 07.11.2012    source источник
comment
да, вы не правильно делаете свой FindControl. Ваш родительский повторитель содержит много ответов lvwAnswers. Может быть, вы можете попробовать что-то вроде приведения rb1.Parent.Parent (или rb1.BindingContainer.Parent) к ListView   -  person jbl    schedule 07.11.2012


Ответы (2)


Если вы просто создаете список переключателей для ответов, вы можете использовать RadioButtonList элемент управления. Это создаст правильный HTML-код, чтобы можно было выбрать только один ответ на вопрос без необходимости обратной отправки, чтобы отменить выбор других вариантов.

Если ваш шаблон ответа содержит более одного RadioButton, все становится сложнее. Когда он не размещен в RadioButtonList, RadioButton использует UniqueID родительского NamingContainer для создания своего уникального имени группы. К сожалению, в вашем примере NamingContainer будет ListViewDataItem из списка lvwAnswers, и у каждого ответа будет свой ID.

Что вам нужно, так это RadioButton, который будет смотреть на NamingContainer NamingContainer, чтобы сгенерировать имя своей группы. Вы можете либо повторно реализовать элемент управления RadioButton, либо использовать немного отражения для обновления закрытого поля _uniqueGroupName:

[ToolboxData("<{0}:ListRadioButton runat=\"server\" />")]
public class ListRadioButton : RadioButton
{
   private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
   private string _uniqueGroupName;

   private static FieldInfo FindUniqueGroupNameField()
   {
      return typeof(RadioButton).GetField("_uniqueGroupName", 
         BindingFlags.NonPublic | BindingFlags.Instance);
   }

   protected virtual string CreateUniqueGroupName()
   {
      string result = GroupName;
      if (string.IsNullOrEmpty(result))
      {
         result = ID;
      }
      if (string.IsNullOrEmpty(result))
      {
         result = UniqueID;
      }
      else
      {
         Control container = NamingContainer;
         if (container != null)
         {
            if (container is IDataItemContainer)
            {
               container = container.NamingContainer ?? container;
            }

            result = container.UniqueID + base.IdSeparator + result;
         }
         else
         {
            string uniqueID = UniqueID;
            if (!string.IsNullOrEmpty(uniqueID))
            {
               int index = uniqueID.LastIndexOf(base.IdSeparator);
               if (index != -1)
               {
                  result = uniqueID.Substring(0, 1 + index) + result;
               }
            }
         }
      }

      return result;
   }

   private void EnsureUniqueGroupName()
   {
      if (_uniqueGroupName == null)
      {
         string value = CreateUniqueGroupName();
         if (UniqueGroupNameField != null) UniqueGroupNameField.SetValue(this, value);
         _uniqueGroupName = value;

         value = base.Attributes["value"];
         if (string.IsNullOrEmpty(value))
         {
            base.Attributes["value"] = UniqueID;
         }
      }
   }

   protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
   {
      EnsureUniqueGroupName();
      return base.LoadPostData(postDataKey, postCollection);
   }

   protected override void Render(HtmlTextWriter writer)
   {
      EnsureUniqueGroupName();
      base.Render(writer);
   }
}

Имея этот элемент управления и зарегистрированный с использованием префикса site, вы можете изменить свой код на:

<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
<LayoutTemplate>
   <asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
   <%# Eval("DESCRIPTION") %>
   <asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
   <LayoutTemplate>
      <asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
   </LayoutTemplate>
   <ItemTemplate>
      <site:ListRadioButton ID="rdbSelect" runat="server"
         Text='<%# Eval("Description") %>'
      />
   </ItemTemplate>
   </asp:ListView>
</ItemTemplate>
</asp:ListView>

В отрендеренном HTML переключатели для каждого вопроса будут иметь одинаковые name, и вы сможете выбрать только один ответ на вопрос, без необходимости публиковать всю страницу для каждого выбора.

person Richard Deeming    schedule 07.11.2012
comment
Это довольно хорошее решение. Наверное, глупый вопрос: почему бы вам не переопределить также LoadViewState и SaveViewState? - person jbl; 08.11.2012
comment
Потому что больше ничего не нужно сохранять в ViewState. Поле _uniqueGroupName создается заново при каждом запросе. - person Richard Deeming; 08.11.2012

Я хотел бы отметить, что этот код «копировать/вставить» не работает и был взят из комментарий к codeproject (комментарий под названием "Другой вариант"). Оригинальный код работает.

Вот :

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class SimpleRadioButton : RadioButton
{
    private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
    private string _uniqueGroupName;

    private static FieldInfo FindUniqueGroupNameField()
    {
        return typeof(RadioButton).GetField("_uniqueGroupName",
            BindingFlags.NonPublic | BindingFlags.Instance);
    }

    protected virtual string CreateUniqueGroupName()
    {
        string result = this.GroupName;
        if (string.IsNullOrEmpty(result))
        {
            result = this.ID;
        }
        if (string.IsNullOrEmpty(result))
        {
            result = this.UniqueID;
        }
        else
        {
            Control container = this.NamingContainer;
            if (null != container)
            {
                if (container is IDataItemContainer)
                {
                    container = container.NamingContainer ?? container;
                }

                result = container.UniqueID + base.IdSeparator + result;
            }
            else
            {
                string uniqueID = this.UniqueID;
                if (!string.IsNullOrEmpty(uniqueID))
                {
                    int index = uniqueID.LastIndexOf(base.IdSeparator);
                    if (-1 != index)
                    {
                        result = uniqueID.Substring(0, 1 + index) + result;
                    }
                }
            }
        }

        return result;
    }

    private void EnsureUniqueGroupName()
    {
        if (null == _uniqueGroupName)
        {
            string value = this.CreateUniqueGroupName();
            if (null != UniqueGroupNameField) UniqueGroupNameField.SetValue(this, value);
            _uniqueGroupName = value;

            // Make sure we have a value attribute:
            value = base.Attributes["value"];
            if (string.IsNullOrEmpty(value))
            {
                base.Attributes["value"] = this.UniqueID;
            }
        }
    }

    protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        this.EnsureUniqueGroupName();
        return base.LoadPostData(postDataKey, postCollection);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        this.EnsureUniqueGroupName();
        base.Render(writer);
    }
}
person Mathlec    schedule 14.11.2012
comment
Это не было взято из комментария к CodeProject; он был основан на том же коде, который я использовал для публикации этого комментария! (Посмотрите на мое настоящее имя в моем профиле SO и сравните его с моим именем в CodeProject.) - person Richard Deeming; 16.11.2012
comment
Кроме того, код из моего ответа здесь идентичен моему комментарию к CodeProject (за исключением имени класса и некоторых незначительных косметических изменений). Это работает для меня и работает для ОП, поэтому я не знаю, почему вы думаете, что это не так? - person Richard Deeming; 16.11.2012
comment
Мои извенения. Я пытался убедиться, что это не было украдено у кого-то еще. Что касается неработающего кода, то это было не для меня. Но я мог ошибиться или использовать его в динамическом контроле. - person Mathlec; 20.11.2012