I am trying to generate a dynamic radio button list, but the issue is that the dynamic list does not show on page load. Only the Submit button shows. Here is the code I am using:
<asp:PlaceHolder runat="server" ID="PlaceHolder1"/>
<asp:Button runat="server" ID="Button1" OnClick="Button1_Click" Text="Submit" />
<asp:Label runat="server" ID="Label1"/>
protected void Page_Load(object sender, EventArgs e)
{
LoadControls();
}
protected void Button1_Click(object sender, EventArgs e)
{
var radioButtonList = PlaceHolder1.FindControl("1") as RadioButtonList;
Label1.Text = radioButtonList.SelectedValue;
}
private void LoadControls()
{
var tmpRBL = new RadioButtonList();
tmpRBL.ID = "1";
for (int i = 1; i <= 5; i++)
{
var tmpItem = new ListItem(i.ToString(), i.ToString());
tmpRBL.Items.Add(tmpItem);
}
PlaceHolder1.Controls.Add(tmpRBL);
}
WebForm1.aspx
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder runat="server" ID="PlaceHolder1"/>
<asp:Button runat="server" ID="Button1" OnClick="Button1_Click" Text="Submit" />
<asp:Label runat="server" ID="Label1"/>
</div>
</form>
</body>
</html>
WebForm1.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
LoadControls();
}
protected void Button1_Click(object sender, EventArgs e)
{
var radioButtonList = PlaceHolder1.FindControl("1") as RadioButtonList;
Label1.Text = radioButtonList.SelectedValue;
}
private void LoadControls()
{
var tmpRBL = new RadioButtonList();
tmpRBL.ID = "1";
for (int i = 1; i <= 5; i++)
{
var tmpItem = new ListItem(i.ToString(), i.ToString());
tmpRBL.Items.Add(tmpItem);
}
PlaceHolder1.Controls.Add(tmpRBL);
}
}
}
It works correct. I hope it will be helpful.
You could define an empty RadioButtonList control which you then populate with items on Page_Load. Would have the advantage that you don't have to create it manually. Also using the DataBind mechanism the control offers you together with an ObjectDataSource is a better solution (the Select method of the ObjectDataSource should return the items).
But aside this, maybe AutoEventWireup of the #Page directive (first line in the markup of the ASPX page) is set to false. If so the Page_Load event handler is not called. The directive usually looks like this:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
I copied the rest of your code and everything runs just fine.
Related
Edit: Sadly, nobody seems to know. Maybe this will help clarify my dilemma: I'm trying to implement my own DataList type of control that supports switching from ItemTemplate to EditItemTemplate. The problem occurs when clicking on a button inside the EditItemTemplate -- it doesn't trigger the handler unless you click a second time!
Sorry about the lengthy post. The code is complete, but hopefully with nothing distracting.
I'm trying to create my own User Control that accepts multiple templates. I'm partly following techniques 39 and 40 from "ASP.NET 4.0 in Practice" by Manning. It seems to be working, except the button inside the template isn't bound to the handler until the second click (after one extra postback).
There are four files involved. Default.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%# Register Src="~/TheTemplate.ascx" TagPrefix="TT" TagName="TheTemplate" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<TT:TheTemplate ID="tt" runat="server">
<ATemplate>
<p>This is template A</p>
<asp:Button ID="TemplateAButton" OnClick="TemplateAButton_Click" runat="server" Text="Template A Button" />
</ATemplate>
<BTemplate>
<p>This is template B</p>
<asp:Button ID="TemplateBButton" OnClick="TemplateBButton_Click" runat="server" Text="Template B Button" />
</BTemplate>
</TT:TheTemplate>
<br />
<asp:Button ID="ToggleTemplate" Text="Toggle Template" OnClick="ToggleTemplate_Click" runat="server" />
</div>
</form>
</body>
</html>
Default.aspx.cs:
using System;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Trace.IsEnabled = true;
tt.DataBind();
}
protected void ToggleTemplate_Click(object sender, EventArgs e)
{
tt.TemplateName = (tt.TemplateName == "A") ? "B" : "A";
tt.DataBind();
}
public void TemplateAButton_Click(object sender, EventArgs e)
{
Trace.Write("TemplateAButton_Click");
}
public void TemplateBButton_Click(object sender, EventArgs e)
{
Trace.Write("TemplateBButton_Click");
}
}
And the user control, TheTemplate.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="TheTemplate.ascx.cs" Inherits="TheTemplate" %>
<p>Using template <asp:Literal Text="<%# TemplateName %>" ID="Literal1" runat="server"></asp:Literal></p>
<asp:Placeholder runat="server" ID="PlaceHolder1" />
And finally, TheTemplate.ascx.cs:
using System;
using System.Web.UI;
[ParseChildren(true)]
public class TheTemplateContainer : Control, INamingContainer
{
private TheTemplate parent;
public TheTemplateContainer(TheTemplate parent)
{
this.parent = parent;
}
}
public partial class TheTemplate : System.Web.UI.UserControl, INamingContainer
{
public string TemplateName
{
get { return (string)(ViewState["TemplateName"] ?? "A"); }
set { ViewState["TemplateName"] = value; }
}
[TemplateContainer(typeof(TheTemplateContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ATemplate { get; set; }
[TemplateContainer(typeof(TheTemplateContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate BTemplate { get; set; }
protected override void OnDataBinding(EventArgs e)
{
TheTemplateContainer container = new TheTemplateContainer(this);
if (TemplateName == "A")
ATemplate.InstantiateIn(container);
else if (TemplateName == "B")
BTemplate.InstantiateIn(container);
PlaceHolder1.Controls.Clear();
PlaceHolder1.Controls.Add(container);
EnsureChildControls();
base.OnDataBinding(e);
}
}
When you first run it, you will see ATemplate being used:
If you click on the Toggle Template button, all the text is correctly rendered:
But clicking on either "Template A Button" or "Template B Button" will not trigger the OnClick handler on the first try:
It will work on the second click:
Does the problem have to do with where .DataBind() is being called?
I'm not quite sure I understand it, but the problem has to do with how newly-added controls go through the "catch-up" events. Removing PlaceHolder1 and adding it programmatically solves the issue. TheTemplate.ascx becomes:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="TheTemplate.ascx.cs" Inherits="TheTemplate" %>
<p>Using template
<asp:Literal Text="<%# TemplateName %>" ID="Literal1" runat="server"></asp:Literal></p>
... and in TheTemplate.ascx.cs, replace OnDataBinding like this:
protected override void OnDataBinding(EventArgs e)
{
TheTemplateContainer container = new TheTemplateContainer(this);
if (TemplateName == "A")
ATemplate.InstantiateIn(container);
else if (TemplateName == "B")
BTemplate.InstantiateIn(container);
System.Web.UI.WebControls.PlaceHolder PlaceHolder1 = new System.Web.UI.WebControls.PlaceHolder();
//PlaceHolder1.Controls.Clear();
PlaceHolder1.Controls.Add(container);
this.Controls.Clear();
this.Controls.Add(PlaceHolder1);
EnsureChildControls();
base.OnDataBinding(e);
}
In the future, if I ever feel like I need to add controls dynamically, I will also create a PlaceHolder dynamically and use that as the root. When PlaceHolder is populated, I will then add it to the page.
I want the user to be able to delete a UserControl by clicking on a Delete button located inside that UserControl.
The btnAddChoice is working fine but the btnRemove is inside the UserControl and btnRemove_Click is not triggered.
Here is my ShowChoices.aspx code :
<div>
<strong>Choices</strong>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="true">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnAddChoice" EventName="Click" />
</Triggers>
<ContentTemplate>
<ul class="list-unstyled">
<asp:PlaceHolder runat="server" ID="phChoices">
</asp:PlaceHolder>
</ul>
</ContentTemplate>
</asp:UpdatePanel>
</div>
Here is my ShowChoices.aspx.cs code :
protected void btnAddChoice_Click(object sender, EventArgs e)
{
Choice ctl = (Choice)LoadControl("~/Controls/Choice.ascx");
ctl.ID = "choice" + PersistedControls.Count;
int j = PersistedControls.Count + 1;
ctl.SetSummary("Choice #" + j);
phChoices.Controls.Add(ctl); // the UserControl is added here
PersistedControls.Add(ctl);
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = ctl.BtnRemoveUniqueID; // problem : BtnRemoveUniqueID = always null
trigger.EventName = "Click";
UpdatePanel1.Triggers.Add(trigger);
}
In Choice.ascx :
<asp:Button ID="btnRemove" CssClass="btn-default" runat="server" Text="Remove this choice" CausesValidation="false" OnClick="btnRemove_Click"/>
In Choice.ascx.cs
protected void btnRemove_Click(object sender, EventArgs e)
{
this.Parent.Controls.Remove(this);
List<Control> _persistedControls = (List<Control>) Session[Step2.PersistedControlsSessionKey];
_persistedControls.Remove(this);
Session[Step2.PersistedControlsSessionKey] = _persistedControls;
UpdatePanel ctl = (UpdatePanel) this.Parent.FindControl("UpdatePanel1");
if (ctl != null)
{
ctl.Update();
}
}
A user control creates a separate naming container, which means additional work is required for your update panel (the SO answer here does a good job explaining it: Trigger an update of the UpdatePanel by a control that is in different ContentPlaceHolder)
This is a fully working example of exposing a button inside a user control so it can act as a trigger and fire events in the parent page. The button is exposed using a public property on the child control, and then all of the event handlers are attached in the parent.
Default.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%# Register Src="~/TestChildControl.ascx" TagName="Custom" TagPrefix="TestChildControl" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" />
<div>
<asp:UpdatePanel runat="server" ID="updTest">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnAddControl" EventName="Click" />
</Triggers>
<ContentTemplate>
<asp:Placeholder runat="server" ID="phControlContainer"></asp:Placeholder>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button runat="server" ID="btnAddControl" Text="Add Control" OnClick="btnAddControl_OnClick" />
</div>
</form>
</body>
</html>
Default.aspx.cs
Note that the child controls have to be recreated on Page Load in the same order with the same IDs in order for events to fire properly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (ControlIDs != null)
{
foreach (string controlID in ControlIDs)
{
AddChildControl(controlID);
}
}
}
protected void btnAddControl_OnClick(object sender, EventArgs e)
{
var rand = new Random();
var controlID = string.Format("TestChildControl_{0}", rand.Next());
AddChildControl(controlID);
}
protected void AddChildControl(string controlID)
{
TestChildControl childControl = (TestChildControl)LoadControl("~/TestChildControl.ascx");
childControl.ID = controlID;
phControlContainer.Controls.Add(childControl);
childControl.RemoveControlButton.Click += btnRemoveControl_OnClick;
AsyncPostBackTrigger updateTrigger = new AsyncPostBackTrigger() { ControlID = childControl.RemoveControlButton.UniqueID, EventName = "click" };
updTest.Triggers.Add(updateTrigger);
SaveControlIDs();
}
private void SaveControlIDs()
{
ControlIDs = phControlContainer.Controls.Cast<Control>().Select(c => c.ID).ToList();
}
protected void btnRemoveControl_OnClick(object sender, EventArgs e)
{
var removeButton = sender as Button;
if (removeButton == null)
{
return;
}
var controlID = removeButton.CommandArgument;
var parentControl =
phControlContainer.Controls.Cast<TestChildControl>().FirstOrDefault(c => c.ID.Equals(controlID));
if (parentControl != null)
{
phControlContainer.Controls.Remove(parentControl);
}
SaveControlIDs();
}
protected IEnumerable<string> ControlIDs
{
get
{
var ids = ViewState["ControlIDs"] ?? new List<string>();
return (IEnumerable<string>) ids;
}
set { ViewState["ControlIDs"] = value; }
}
}
TestChildControl.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="TestChildControl.ascx.cs" Inherits="TestChildControl" %>
<div>
This is a test control
</div>
<div>
<asp:Button runat="server" ID="btnRemoveControl" Text="Remove Control" />
</div>
TestChildControl.ascx.cs
Note that here we expose the button as a read-only property so we can assign event handlers to it and access its members. I assigned the parent control ID as the CommandArgument as a matter of convenience.
using System;
using System.Web.UI.WebControls;
public partial class TestChildControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
btnRemoveControl.CommandArgument = this.ID;
}
public Button RemoveControlButton
{
get { return btnRemoveControl; }
}
}
I'm using a Repeater to show some data coming from a web service.
My Repeater structure is:
<asp:Repeater ID="rptgrp" runat="server">
<ItemTemplate>
<asp:CheckBoxList ID="chkBoxListGoup" runat="server"
DataSource='<%# DataBinder.Eval(Container.DataItem, "Titles")%>'
DataTextField="Title"
DataValueField="IDTitle">
</asp:CheckBoxList>
</ItemTemplate>
</asp:Repeater>
Now, my web service returns these fields in "Titles":
1) Title
2) IDTitle
3) isUserTitle
Now, I would like to set checked a checkbox when isUserTitle is = 1.
How can I do that?
You can find checkboxlist as follows
Find checkboxlist in itemdatabound,
check item text of every checkboxlist using loop,
select the item whose text is 1
Protected void Repeater_ItemDataBound(Object Sender, RepeaterItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
CheckBoxList chklst = (CheckBoxList)e.Item.FindControl("chkBoxListGoup");
for (int i = 0; i < chk.Items.Count; i++)
{
if (chk.Items[i].Text == "1")
{
chk.Items[i].Selected = true;
}
}
}
}
Try changing <asp:CheckBoxList ID="chkBoxListGoup" runat="server"
to
<asp:CheckBoxList ID="chkBoxListGoup" Checked='<%#Eval("Flag")%>' runat="server"
Flag being your Column..
Then in your method or event handler you want to run some code to say if this value = 1 checked, elseif value = 0 unchecked...
Here is sample code that demonstrates the idea:
Code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using WebApp.RepeaterCheckboxList.TODODatasetTableAdapters;
namespace WebApp.RepeaterCheckboxList
{
public partial class WebForm1 : System.Web.UI.Page
{
IEnumerable<TODODataset.TasksViewRow> view;
IEnumerable<TODODataset.TasksViewRow> subview;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TasksViewTableAdapter adp = new TasksViewTableAdapter();
var dt = adp.GetData();
view = dt.AsEnumerable();
var names = (from x in view
select new
{
Person = x.Name,
ID = x.PersonID
}).Distinct();
DataList1.DataSource = names;
DataList1.DataBind();
}
}
protected void CheckBoxList1_DataBound(object sender, EventArgs e)
{
CheckBoxList theList = (CheckBoxList)sender;
var person = ((DataListItem)theList.Parent).DataItem as dynamic;
var name = person.Person;
var id = person.ID;
var vw = subview;
for (int i = 0, j = vw.Count(); i < j; i++)
{
var task = vw.ElementAt(i);
theList.Items[i].Selected = task.Completed;
}
}
protected IEnumerable<TODODataset.TasksViewRow> GetTasks(object data)
{
var vw = data as dynamic;
return subview = (from x in view
where x.PersonID == vw.ID
select x);
}
}
}
Aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApp.RepeaterCheckboxList.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DataList ID="DataList1" runat="server">
<ItemTemplate>
<div style="padding:5px">
<h3><%# Eval("Person") %></h3>
<div>
<asp:CheckBoxList OnDataBound="CheckBoxList1_DataBound" ID="CheckBoxList1"
runat="server"
DataTextField="TaskDesc" DataValueField="TaskID"
DataSource="<%# GetTasks(Container.DataItem) %>"></asp:CheckBoxList>
</div>
</div>
</ItemTemplate>
</asp:DataList>
</div>
</form>
</body>
</html>
If you are interested in the data, click here
Try just setting the Checked value to the object being Evaled.
<asp:Repeater ID="rptgrp" runat="server">
<ItemTemplate>
<asp:CheckBoxList ID="chkBoxListGoup" runat="server"
Checked=<%# Eval("isUserTitle") %>>
</asp:CheckBoxList>
</ItemTemplate>
</asp:Repeater>
I have this program in asp.net using C#
.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div id="first" runat="server">
Text Boxes
<asp:TextBox ID="txtnr" runat="server"></asp:TextBox><br />
<asp:Button ID="btnxt1" runat="server" Text="Next" onclick="btnxt1_Click"/><br />
</div>
<div id="second" runat="server">
<asp:Table ID="tbl" runat="server"></asp:Table>
<asp:Button ID="btnx2" runat="server" Text="Next" onclick="btnx2_Click"/><br />
</div>
<div id="third" runat="server">
<asp:Label ID="lblxx" runat="server" Text=""></asp:Label><br />
</div>
</form>
</body>
</html>
.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
static int numr = 0;
static TableHeaderCell[] tc2;
static TextBox[] txtb;
protected void Page_Load(object sender, EventArgs e){}
protected void btnxt1_Click(object sender, EventArgs e)
{
numr = int.Parse(txtnr.Text);
TableHeaderRow tr;
tc2 = new TableHeaderCell[numr];
txtb = new TextBox[numr];
for (int i = 0; i < numr; i++)
{
tr = new TableHeaderRow();
tc2[i] = new TableHeaderCell();
txtb[i] = new TextBox();
txtb[i].Text = "w";
tc2[i].Controls.Add(txtb[i]);
tr.Controls.Add(tc2[i]);
tbl.Controls.Add(tr);
}
}
protected void btnx2_Click(object sender, EventArgs e)
{
for (int i = 0; i < numr; i++)
lblxx.Text += txtb[i].Text+"<br/>";
}
}
Program steps:
enter number of text-boxes to appear (say = 4) and click 'Next'
four text-boxes will appear (the program sets the value of textbox = "w",to understand the problem)
user can set other value for the text for the four text boxes (say: 1 , 2 , 3 , 4) then click next
finally, the program print the values of text boxes, but the problem is the program
will print: wwww not "1234" :( ??
How to fix this problem??
The problem is due to the fact that dynamic controls (like yours) do not automatically maintain their state after a post back and you should handle it on your own.
Please follow this link for a very similar question and then this link for the corresponding solution.
I've got a multiple step webform written in c#/asp.net. I'm trying to change the url that posts back to for google analytics reasons. I've written the code below to change the url on the client side, but it doesn't seem to post to the url with the parameters on the end. Almost like it's being changed back on the client side onsubmit. Any ideas?
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="TestNamespace.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body onload="setaction(<%= step %>);">
<form id="form1" runat="server">
<div>
<asp:Label ID="lblCurrentUrl" runat="server"></asp:Label>
<asp:Panel ID="panel1" runat="server">
Panel 1<asp:Button ID="Button1" runat="server" onclick="Button1_Click"
Text="Button" />
</asp:Panel>
<asp:Panel ID="panel2" runat="server" Visible="false">
Panel 2<asp:Button ID="Button2" runat="server" onclick="Button2_Click"
Text="Button" />
</asp:Panel>
<asp:Panel ID="panel3" runat="server" Visible="false">
Panel 3<asp:Button ID="Button3" runat="server" onclick="Button3_Click"
Text="Button" />
</asp:Panel>
<asp:Panel ID="panel4" runat="server" Visible="false">
Panel 4<asp:Button ID="Button4" runat="server" onclick="Button4_Click"
Text="Button" />
</asp:Panel>
</div>
<script language="javascript" type="text/javascript">
function setaction(step) {
var bdy = document.getElementsByTagName("body")[0];
bdy.setAttribute("action", "webform1.aspx?step=" + step);
alert(document.location.href);
}
</script>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace TestNamespace
{
public partial class WebForm1 : System.Web.UI.Page
{
protected int step;
protected void Page_Load(object sender, EventArgs e)
{
lblCurrentUrl.Text = Request.Url.ToString();
if ( IsPostBack ) return;
step = 1;
}
protected void Button1_Click(object sender, EventArgs e)
{
panel1.Visible = false;
panel2.Visible = true;
step = 2;
}
protected void Button2_Click(object sender, EventArgs e)
{
panel2.Visible = false;
panel3.Visible = true;
step = 3;
}
protected void Button3_Click(object sender, EventArgs e)
{
panel3.Visible = false;
panel4.Visible = true;
step = 4;
}
protected void Button4_Click(object sender, EventArgs e)
{
}
}
}
It looks like you're setting the action on the body, rather than the form. Unless I'm missing something, you should be able to fix the problem like so:
function setaction(step) {
var frm = document.getElementsByTagName("form")[0];
frm.setAttribute("action", "webform1.aspx?step=" + step);
alert(document.location.href);
}