OnCheckedChanged Nested Listview Controls

懵懂的女人 提交于 2019-12-13 03:18:25

问题


I have the following nested listview...

<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>

I get hold of the radio buttons OnCheckedChanged like so...

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

The problem i have is 'lvwAnswers' is Nothing. I'm guessing im not doing my findcontrol correctly.

Any help greatly appreciated.


回答1:


If you're just generating a list of radio-buttons for the answers, you could use the RadioButtonList control. This would generate the correct HTML so that only one answer could be selected per question without having to post-back to de-select the other options.

If your answer template contains more than a single RadioButton, things get more complicated. When it's not hosted in a RadioButtonList, the RadioButton uses the UniqueID of the parent NamingContainer to build its unique group name. Unfortunately, in your example, the NamingContainer will be the ListViewDataItem from the lvwAnswers list, and each answer will have a different ID.

What you need is a RadioButton which will look at the NamingContainer's NamingContainer to generate its group name. You could either re-implement the RadioButton control, or use a little bit of reflection to update the private _uniqueGroupName field:

[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);
   }
}

With that control in place and registered using the site prefix, you can change your code to:

<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>

In the rendered HTML, the radio-buttons for each question will then have the same name, and you will only be able to select a single answer per question, without having to post the entire page on each selection.




回答2:


I'd like to point out that this "copy/paste" code doesn't work and was taken from a comment on codeproject (Comment titled Another Option). The original code does work.

Here it is :

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);
    }
}


来源:https://stackoverflow.com/questions/13269773/oncheckedchanged-nested-listview-controls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!