Retrieve value for selected radiobutton in ListView asp.net - asp.net

I would like to send a Guid which should be associated with each radio button as eventargs when the user clicks checkout. I was able to achieve this functionality with just a RadioButtonList but I cannot use that here as the rest of the fields are pulled from the database.
There are numerous questions dealing with this type of topic but I could not find one that addresses exactly what I am trying to achieve.
I have the below list
<asp:Content ID="SubscriptionContent" ContentPlaceHolderID="MainContent" ViewStateMode="Enabled" runat="server">
<asp:Panel ID="SubscriptionPanel" CssClass="shopping-cart" ViewStateMode="Enabled" runat="server">
<asp:ListView ID="NewSubscription" runat="server">
<LayoutTemplate>
<table class="table">
<thead>
<th>Select a Subscription</th>
<th>Subscription Level
</th>
<th>Description
</th>
<th>Price
</th>
</thead>
<tbody>
<tr id="itemPlaceholder" runat="server" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td class="description"><asp:RadioButton ID="SubscriptionLevel" GroupName="SubscriptionRadio" Text='<%# Eval("SubscriptionLevel") %>' runat="server" /></td>
<td class="description"><asp:Label ID="Details" Text='<%# Eval("Details") %>' runat="server"></asp:Label></td>
<td class="price"><asp:Label runat="server" Text='<%# Eval("Price", "{0:C2}") %>'></asp:Label></td>
<asp:TextBox ID="Id" runat="server" Visible="false" Text='<%# Eval("Id") %>' />
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Button ID="Subscribe" CssClass="btn btn-primary" runat="server" Text="<%$ Snippet: Ecommerce/ShoppingCart/CheckoutButtonLabel, Checkout %>" OnClick="BuySubscription" />
<script type="text/javascript">
$(document).ready(function () {
$("input:radio").attr('name', 'SubscriptionRadio');//Override the naming that asp does
});
</script>
</asp:Panel>
</asp:Content>
I am thinking that if I could update a hidden field with the corresponding guid value for each radio button and submit that when the user triggers BuySubscription. I am not sure how to do this though. Ultimately I just want the user to be able to select one of the subscription options and pass that guid back to the function.
Thank you in advance for any input.

The first problem you're going to run into is that ASP.NET gives each <input type="radio" /> a different name, because it's in a different NamingContainer.
You've added some script to try to work around that by changing the name attribute on the client. Unfortunately, this won't work. When you post the form back to the server, ASP.NET will still be looking for a value using the generated name, which won't exist.
The quick and dirty solution would be to update your script to copy the value from the hidden TextBox to the value attribute of the radiobutton. You would then have to use Request.Form["SubscriptionRadio"] to retrieve the value of the selected option:
<ItemTemplate>
<tr>
<td class="description">
<asp:RadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
/>
<%-- NB: Can't set Visible="False", otherwise it's not rendered: --%>
<asp:TextBox ID="Id" runat="server"
Style="display:none;"
Text='<%# Eval("Id") %>'
/>
</td>
...
</tr>
</ItemTemplate>
...
<script>
$(document).ready(function() {
$("input:radio").each(function(){
var me = $(this);
var id = me.closest("tr").find("input[name$=Id]").val();
me.attr("value", id);
me.attr('name', 'SubscriptionRadio');
});
});
</script>
Alternatively, you could use a custom RadioButton control which works within a data-bound control. I posted a simple example back in 2012: https://stackoverflow.com/a/13271444/124386
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SiteControls
{
[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);
}
public string Value
{
get { return Attributes["value"]; }
set { Attributes["value"] = value; }
}
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);
}
}
}
You can either register the control in the page markup:
<%# Register tagPrefix="site" namespace="SiteControls" %>
or in the web.config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<pages>
<controls>
<add
tagPrefix="site"
namespace="SiteControls"
/>
</controls>
</pages>
</system.web>
</configuration>
With that in place, you can lose the script and the hidden TextBox:
<ItemTemplate>
<tr>
<td class="description"><site:ListRadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
Value='<%# Eval("Id") %>'
/></td>
...
To find the selected item, you would then need to loop through the ListView's Items, find the RadioButton control, and look at the Checked property:
ListRadioButton selectedItem = NewSubscription.Items
.Select(item => (ListRadioButton)item.FindControl("SubscriptionLevel"))
.FirstOrDefault(radio => radio != null && radio.Checked);
string selectedValue = (selectedItem == null) ? null : selectedItem.Value;

Related

Required Field Validator not working on controls inside dynamically generated user control

I have a user control containing few server controls like text boxes and drop down lists.
i have also added few required field validation controls. Normally these validation work fine, if I add the user control in design time.
But when I add the user control dynamically, the validation control just don’t work and page is posted back.
User Control:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="myUserControl.ascx.cs" Inherits="myUserControl" %>
<table cellpadding="0" cellspacing="0" >
<tr>
<td>
<asp:TextBox runat="server" ID="txtLastName" Width="80px" MaxLength="64" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="txtLastName" runat="server" ErrorMessage="Required Value" Display="None"></asp:RequiredFieldValidator>
<ajaxToolkit:ValidatorCalloutExtender ID="ValidatorCalloutExtender1" runat="server" TargetControlID="RequiredFieldValidator1"></ajaxToolkit:ValidatorCalloutExtender>
</td>
<td>
<asp:TextBox runat="server" ID="txtFirstName" Width="80px" MaxLength="64" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" ControlToValidate="txtFirstName" runat="server" ErrorMessage="Required Value" Display="None"></asp:RequiredFieldValidator>
<ajaxToolkit:ValidatorCalloutExtender ID="ValidatorCalloutExtender2" runat="server" TargetControlID="RequiredFieldValidator2"></ajaxToolkit:ValidatorCalloutExtender>
</td>
<td>
<asp:Button ID="btnDelete" runat="server" Text="Delete" OnClick="DeleteButton_Click" CausesValidation="false" />
</td>
</tr>
</table>
Containing Form Markup:
<form id="form1" runat="server">
<div>
<div align="right" ><asp:Button ID="btnAdd" runat="server" Text="Add Order Line" onclick="btnAdd_Click" CausesValidation="false" /></div>
<asp:PlaceHolder runat="server" ID="DynamicNameList" />
<asp:Button ID="btnSubmit" runat="server" Text="Submit" onclick="btnSubmit_Click" />
</div>
</form>
Containing Form Code:
public partial class WebForm1 : System.Web.UI.Page, IDynamicControlContainer
{
protected void Page_Load(object sender, EventArgs e)
{
foreach (string id in LoadControlIdList())
{
Create(id);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
}
protected void btnAdd_Click(object sender, EventArgs e)
{
Create(null);
}
public void Create(string id)
{
string targetId = id ?? Guid.NewGuid().ToString();
myUserControl control = LoadControl("~/CustomControls/myUserControl.ascx") as myUserControl;
control.ID = targetId;
DynamicNameList.Controls.Add(control);
SaveControlIdList();
}
public void Delete(Control control)
{
DynamicNameList.Controls.Remove(control);
SaveControlIdList();
}
public void SaveControlIdList()
{
List<string> idList = new List<string>();
foreach (Control control in DynamicNameList.Controls)
{
idList.Add(control.ID);
}
ViewState["IdList"] = idList;
}
public string[] LoadControlIdList()
{
var list = (List<string>)ViewState["IdList"];
if (list == null)
{
return new string[0];
}
return list.ToArray();
}
}
public interface IDynamicControlContainer
{
/// <summary>
/// Deletes the specified control from the container
/// </summary>
/// <param name="control">The control.</param>
void Delete(Control control);
}
}
You need to use either the Page_Init or CreateChildControls events to do this. By the time Page_Load kicks in, the control tree is already loaded.

How to get item click event in asp.net repeater control?

I am using a repeater control to show some data on my page.
The repeater item template has an image and a label field.
I want that when i click the image , I get an event containing the id field of my data item.
How can I achieve this ?
Actually when I click the image i want to go to another page and want to show detailed information of my data item, in repeater i m just showing short information.
My repeater looks like this:
<asp:Repeater ID="itemRepeater" runat="server" OnItemCreated="itemRepeater_ItemCreated" >
<ItemTemplate>
<tr>
<td colspan="2">
<asp:Image ID="phImage" runat="server" ImageUrl='<%#"~/ImageHandler.ashx?id=" + DataBinder.Eval(Container.DataItem, "PhotoID")%>' />
</td>
<td>
<asp:Label ID="lblImageName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
I want to get PhotoID in the event when i click the image.
My photo class looks like this:
public class PhotoDC
{
public byte[] ImagebyteArray { get; set; }
public string Name { get; set; }
public int PhotoID { get; set; }
}
I have been doing winform programming just started web, maybe it is easy but i m struggling to find a solution.
I somehow managed to show hand cursor when i hover the image though.
Try this:
<asp:Repeater ID="itemRepeater" runat="server" OnItemCreated="itemRepeater_ItemCreated" >
<ItemTemplate>
<tr>
<td colspan="2">
<asp:ImageButton ID="phImage" runat="server" ImageUrl='<%#"~/ImageHandler.ashx?id=" + DataBinder.Eval(Container.DataItem, "PhotoID")%>' OnCommand="Image_Click" CommandName="ImageClick" CommandArgument='<%# Eval("PhotoID") %>' />
</td>
<td>
<asp:Label ID="lblImageName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
protected void Image_Click(object sender, CommandEventArgs e)
{
if (e.CommandName == "ImageClick"){
//e.CommandArgument --> photoid value
//Do something
}
}
You can use ItemCommand of repeater control
like this -
protected void itemRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
if (e.CommandName == "img_Click") // check command is cmd_delete
{
// get you required value
int CustomerID = Convert.ToInt32(e.CommandArgument);
//Write some code for what you need
}
}
}
Personally I think the simplest way to handle something like this is to simply use the ItemTemplate to generate a regular html link, rather than do any thing in the code-behind. Something like this:
<asp:Repeater ID="itemRepeater" runat="server" OnItemCreated="itemRepeater_ItemCreated" >
<ItemTemplate>
<tr>
<td colspan="2">
<a href="/Details.aspx?id=<%=DataBinder.Eval(Container.DataItem, "PhotoID")%>">
<asp:Image ID="phImage" runat="server" ImageUrl='<%#"~/ImageHandler.ashx?id=" + DataBinder.Eval(Container.DataItem, "PhotoID")%>' />
</a>
</td>
<td>
<asp:Label ID="lblImageName" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' />
</td>
</tr>
</ItemTemplate>
I know this isn't strictly the question you asked, but IMHO it's the best approach to accomplish the task.

Passing parameter to user control inside repeater

I have a repeater that lists data including an ID that I pass to a user control that is not visible until I click a linkbutton. However, when I have clicked the linkbutton, the ID has been lost.
Anyone have any idea where I'm going wrong?
Here is the code for the repeater:
<asp:Repeater ID="uxPolicyList" runat="server" onitemdatabound="uxPolicyList_ItemDataBound">
<ItemTemplate>
<tr>
<td class="smaller-ctrl">
<img src="Assets/Images/home-icon.gif" alt="Home Insurance Policy" /><%#Eval("PolicyNumber")%>
</td>
<td>
<%#Eval("StartDate","{0:d}")%>
</td>
<td class="center-cell-ctrl">
<%#Eval("Renewal", "{0:d}")%>
</td>
<td class="center-cell-ctrl">
Postcode:<br />
<%#Eval("Postcode")%>
</td>
<td id='<%#Eval("PolicyNumber")%>' class="button-cell">
<asp:LinkButton ID="uxPolicySummaryButton" CssClass="policy-link-ctrl" CommandName="PolicyNumber" CommandArgument='<%#Eval("PolicyNumber")%>' OnCommand="uxPolicySummaryButton_Command" runat="server">Policy summary<br /></asp:LinkButton>
</td>
</tr>
<uc1:PolicySummary ID="uxPolicySummary" PolicyNumber='<%#Eval("PolicyNumber")%>' runat="server" Visible="false" />
</ItemTemplate>
I have these get/set accessors in the user control code-behind, but they're always blank:
public string _policyNumber = string.Empty;
public string PolicyNumber
{
get
{
return _policyNumber;
}
set
{
_policyNumber = value;
}
}
When testing, I hard coded a value in the user control. i.e.
<uc1:PolicySummary ID="uxPolicySummary" PolicyNumber="545545-5454-54545" runat="server" Visible="false" />
...and it worked fine. Any ideas appreciated
try to reassign value of PolicyNumber property inside OnCommand event with the value of CommandArgument
Edit
or save it into HiddenField inside your control
public string PolicyNumber
{
get
{
return MyHiddenField.Value;
}
set
{
MyHiddenField.Value = value;
}
}
I think you might be missing the ViewState backing store.
public string PolicyNumber
{
get { return ViewState["policyNumber"] as string; }
set { ViewState["policyNumber"] = value; }
}

Getting the password value from a Login control in ASP.net page

I've got my login control in my site Master page:
<AnonymousTemplate>
<asp:Login runat="server" OnLoggedIn="Login1_LoggedIn" CssClass="LoginForm" />
</AnonymousTemplate>
In the code-behind page of this Master page I am trying to capture the value entered in the Password form field. The code works in the homepage, but doesn't work in all other pages!
The code used is:
Page page = (Page)HttpContext.Current.Handler;
TextBox tbtemp = (TextBox)page.FindControl("Password");
_password = tbtemp.ToString();
On the homepage, looking at the trace the value of the Text box is:
ctl00$LoginView1$ctl01$Password
On the other pages the value is:
ctl00$ctl00$LoginView1$ctl01$Password
The error that is thrown on the non-homepage pages is:
due to Exception of type
'System.Web.HttpUnhandledException'
was thrown.
Any ideas how to access the value?
Update:
My login form looks like this:
<asp:loginview id="LoginView1" runat="server">
<LoggedInTemplate >
<asp:LoginStatus ID="LoginStatus1" runat="server" OnLoggedOut="LoginStatus1_LoggedOut" /> <%--Displays the text logged in--%>
<asp:LoginName ID="LoginName1" runat="server" /> <%--displays the username--%>
</LoggedInTemplate>
<AnonymousTemplate>
<asp:Login RememberMeSet="true" ID="loginForm" runat="server" OnLoggedIn="Login1_LoggedIn" CssClass="LoginForm" >
<LayoutTemplate>
<table>
<tr>
<td><asp:Label ID="UserNameLabel" runat="server">Username:</asp:Label></td>
<td><asp:TextBox ID="UserName" runat="server" /></td>
</tr>
<tr>
<td><asp:Label ID="PasswordLabel" runat="server" >Password:</asp:Label></td>
<td><asp:TextBox ID="Password" runat="server" TextMode="Password" /></td>
</tr>
<tr>
<td><asp:Label ID="RememberMeLabel" runat="server" >Remember me: </asp:Label></td>
<td><asp:CheckBox ID="RememberMe" runat="server" /></td>
</tr>
<tr>
<td> </td>
<td> <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In" /></td>
</tr>
</table>
</LayoutTemplate>
</asp:Login>
</AnonymousTemplate>
</asp:loginview>
Why are you getting the password control explicitly? Did you try just getting the password directly from
string password = LoginCtrl.Password //Assuming LoginCtrl is the Id of your control.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.login.aspx
string username = ((Login)this.LoginView.FindControl("LoginControl")).UserName;
// Search recursively a control sub-tree for a specific control.
// It searches every control in the sub-tree, so it potentially
// could be optimized to search only, say, INamingContainers.
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id) return root;
foreach (Control c in root.Controls)
{
var ctlFound = FindControlRecursive(c, id);
if (((ctlFound != null))) return ctlFound;
}
return null;
}
public T FindControl<T>(string id) where T : Control
{
return FindControl<T>(Page, id);
}
public static T FindControl<T>(Control startingControl, string id) where T : Control
{
T found = null;
foreach (Control activeControl in startingControl.Controls)
{
found = activeControl as T;
if (found == null)
{
found = FindControl<T>(activeControl, id);
}
else if (string.Compare(id, found.ID, true) != 0)
{
found = null;
}
if (found != null)
{
break;
}
}
return found;
}
}

How to read ListView data into generic List

I have a ListView which is filled by generic list of type MyClass. I can easily bind data from this list into ListView. But I have problems with reading data in opposite direction.
This is my class:
public class MyClass
{
public int id { get; set; }
public string name { get; set; }
}
I have also generic list of type MyClass:
List<MyTest> list = new List<MyTest>();
Finally I bind data to ListView this way:
ListView1.DataSource = list;
ListView1.DataBind();
My ListView template:
<asp:ListView runat="server" ID="ListView1">
<LayoutTemplate>
<table runat="server" id="table1" >
<tr runat="server" id="itemPlaceholder" ></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr id="tr" runat="server">
<td id="td1" runat="server">
<asp:TextBox ID="tb1" runat="server" Text='<%#Eval("id") %>' />
</td>
<td id="td2" runat="server">
<asp:TextBox ID="tb2" runat="server" Text='<%#Eval("name") %>' />
</td>
</tr>
</ItemTemplate>
How can I read data from ListView into my List list?
The operation of reading ListView data into List generic list should begin after clicking the button "GetData"
I can't test this, but I believe this will work:
using System.Linq;
List<MyClass> list = ListView1.DataSource.Cast<MyClass>().ToList();
UPDATE: As noted in the comments, that only works right after you set the DataSource. If you want to get the list on a post-back, try:
List<MyClass> list = ListView1.Items
.Select(lvi=>lvi.DataItem as MyClass)
.ToList();
You can get at the ListViewItem in an updating event like this:
<asp:ListView ID="ListView1" runat="server" OnItemUpdating="ListView1_ItemUpdating"></asp:ListView>
void ListView1_ItemUpdating(Object sender, ListViewUpdateEventArgs e)
{
ListViewItem item = ListView1.Items[e.ItemIndex];
// I think you should also be able to do if you are indeed binding with the type List<MyTest>
List<MyTest> item = (List<MyTest>)ListView1.Items[e.ItemIndex];
}
I can show you other ways if you describe more of what the scenario is that you need to get the data.

Resources