I want to create a user control that will again contain a user control that will be dynamically generated and can be repeated N times with respect to data present in data table.
How can i do this.
You want to use TemplateControl.LoadControl (which both Page, UserControl and MasterPage inherit from). You need to do this during the Init event for postback stuff to work.
void Page_Init(Object Sender, EventArgs e) {
var control = LoadControl("Awesome.ascx");
// ... Magic!
}
Place a placeholder control on the parent user control:
<asp:PlaceHolder runat="server" id="phMainHolder" />
In the Page_Load or Page_Init event you simply instantiate the child user controls in a for(each) loop and add them to the placeholder like for example:
for(int i = 0; i < 10; i++) {
ChildUC child = new ChildIC();
phMainHolder.Controls.Add(child);
}
This is the bare minimum to do it. You can opt to set properties or whatever on your child controls of course.
The class ChildUC is a fictive class name for this example. Use the class, and if needed use the namespace as extra in which it is defined, of the user control you want to use.
Related
I have an asp.net 4 page with a user control in it. When the user selects a value in a grid inside the user control I would like to update a data source's (in my case a LINQ data source) WHERE clause using a value from the grid. The data source object is in the parent page. The page life cycle loads the parent page before the grid's item command method executes so I am not able to get the selected value.
How can this be done? I would like to do this all server-side if possible.
Create an event in the child page like so:
public event EventHandler DataChanged;
From the child page, call it like this when appropriate:
if (DataChanged != null)
DataChanged(sender, new EventArgs());
Then in the parent page, create a method to be called and attach it like so:
protected void DoSomething(object sender, EventArgs e)
{
}
child.DataChanged += DoSomething;
Oh yeah, I almost forgot. I think you have to set up the event relationship in Page_Init() rather than waiting for Page_Load().
I have a page that has 5 user controls. I want to do more with them, but for now, I just want to count them using the following method.
void btnFormSave_Click(object sender, EventArgs e)
{
int i = 0;
ControlCollection collection = Page.Controls;
foreach (Control ctr in collection)
{
if (ctr is UserControl)
{
i++;
}
}
}
When I debug this code, i = 1, and the control is the master page (I didn't know that the master page is a user control).
How do I count user controls that are on my page?
EDIT
This is my content placeholder markup.
<asp:Content ID="cntMain" runat="Server" ContentPlaceHolderID="ContentMain">
You only need to change where you look for:
void btnFormSave_Click(object sender, EventArgs e)
{
int i = 0;
// here, look inside the form, and not on page.
ControlCollection collection = Page.Form.Controls;
foreach (Control ctr in collection)
{
if (ctr is UserControl)
{
i++;
}
}
}
I have tested and working for me.
EDIT: Replacing my original, off-base answer with the following.
You probably need to recurse to controls within controls (perhaps into a Panel?).
http://msdn.microsoft.com/en-us/library/yt340bh4(v=vs.100).aspx
This example finds only the controls contained in the Page object and
the controls that are direct children of the page. It does not find
text boxes that are children of a control that is in turn a child of
the page. For example, if you added a Panel control to page, the Panel
control would be a child of the HtmlForm control contained by the
Page, and it would be found in this example. However, if you then
added a TextBox control into the Panel control, the TextBox control
text would not be displayed by the example, because it is not a child
of the page or of a control that is a child of the page. A more
practical application of walking the controls this way would be to
create a recursive method that can be called to walk the Controls
collection of each control as it is encountered.
EDIT 2: Adding links to recursive control search examples on SO.
Example using LINQ: https://stackoverflow.com/a/253962/704808
Traditional example: https://stackoverflow.com/a/4955836/704808
protected void lbChatFriend_Click(object sender, EventArgs e)
{
ChatDivContent.Visible = true;
System.Web.UI.HtmlControls.HtmlGenericControl createDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
createDiv.ID = "div";
createDiv.Style.Add(HtmlTextWriterStyle.BackgroundColor, "Yellow");
createDiv.Style.Add(HtmlTextWriterStyle.Position, "relative");
createDiv.Style.Add(HtmlTextWriterStyle.Color, "Red");
createDiv.Style.Add(HtmlTextWriterStyle.Height, "50px");
createDiv.Style.Add(HtmlTextWriterStyle.Width, "50px");
createDiv.InnerHtml = " I'm a div ";
string chatFriend = ((LinkButton)sender).Text;
createDiv.Attributes["title"] = chatFriend;
ChatDivContent.Controls.Add(createDiv);
}
<div id="ChatDivContent">
<DIV id="div" style="background-color:Yellow;position:relative;color:Red;height:50px;width:50px;"
title="dinesh"> I'm a div </DIV></div>
<----This is my output on every postback
Wnat am I doing wrong?
I assume that you're not recreating the old controls on postback(f.e. when the user clicks on that LinkButton). Therefor only the recently created div is displayed.
You have to recreate all dynamically created controls on every postback(in load event at the latest).
You also have to ensure that they get the same ID as before to trigger events and maintain ViewState.
If you know the number of controls to create(which could be stored in ViewState) you can derive the ID from the counter variable by appending it to the control-id. Then you can recreate them with the correct ID in page's init event.
Recommandable readings:
TRULY Understanding Dynamic Controls
Page-Lifecycle
Or you use one of the builtin Data-Bound Control like Repeater that do this automatically. You only have to set their DataSource and call DataBind().
Here is an answer of me on a similar question with implementation.
I have a user control nested in a repeater.
Inside my user control I have another repeater and in that I have a panel.
I am trying to override the LoadViewState event of my user control and dynamically add controls to the panel. I want to do it in the LoadViewState so that the dynamic controls get added before the viewstate gets loaded, so they retain their values after post backs.
For some reason the LoadViewState event on the user control (ascx) is not firing. Is there some way to force it to fire, or is there another method I could use? I have ruled out the user controls repeater databind event, because I need it to work even if data binding isn't happening and I can't do it on the repeaters item created event either because the child panel and inner html doesn't exist yet.
LoadViewState isn't the appropriate place for adding child controls. For dynamically adding controls within a user control, you'll want to look at the CreateChildControls method.
It's not firing a LoadViewState event because you need to save at least one value in the ViewState to have the event fire.
I think I had a similar problem with some dynamically created children user controls. LoadViewState wasn't called in postbacks even if I was able to access their ViewState when creating them first. SaveViewState seemed to be also called correctly. It ended that the children ViewState was not really usable (without this resulting in an exception) in the page Init event before they were fully initializated, and this happened only when the controls were added to the parent. After having ensured this, the children ViewState was correctly persisted across postbacks.
// Belongs to a Page. If you create the children control in the
// Load event in you can also access the page ViewState
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
for (int it = 0; it < 5; it++)
{
ChildControl child = LoadControl("ChildControl.ascx")
as ChildControl;
child.ParentPage = this;
TabPanel tab = tabContainer.FindControl("TabPanel" + it)
as TabPanel;
// Ensure to add the child control to its parent before
// accessing its ViewState!
tab.Controls.Add(child); // <---
string caption = "Ciao" + it;
child.Caption = caption; // Here we access the ViewState
tab.HeaderText = caption;
tab.Visible = true;
_Children.Add(child);
}
}
[...]
}
// Belongs to ChildControl
public string Caption
{
get { return ViewState["Caption"] as string; }
internal set { this.ViewState["Caption"] = value; }
}
I read about the dynamic control creation in ASP.NET this piece of text:
...When using dynamic controls, you
must remember that they will exist
only until the next postback. ASP.NET
will not re-create a dynamically added
control. If you need to re-create a
control multiple times, you should
perform the control creation in the
Page.Load event handler. This has the
additional benefit of allowing you to
use view state with your dynamic
control. Even though view state is
normally restored before the Page.Load
event, if you create a control in the
handler for the Page.Load event,
ASP.NET will apply any view state
information that it has after the
Page.Load event handler ends. This
process is automatic ...
I wanted to try it on example
create a button declaratively -
<asp:Button ID="Button1" runat="server" Text="Button"
onclick="Button1_Click" />
and dynamically on behind code 5 checkboxes -
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i <= 5; i++)
{
var chBox = new HtmlInputCheckBox();
Controls.Add(chBox);
}
}
But when i check some checkboxes and hit the button, after postback all checkboxes
states are erased. It mean ASP.NET does not manage view states of dynamic controls
automatically? I tried to enable view state to each of checkbox and for whole page,
but its doesn't work.
Can someone explain:
1. Why is it so?
2. How to avoid this?
The reason this is happening is because in order for ASP.NET to restored POSTed values, those controls need to be a part of the page before Load. In order to make this work you need to (if possible) create your controls OnInit of the page.
The controls can be created on Page_Init.
protected void Page_Init(object sender, EventArguments e)
{
//Generate the checkboxes dynamically here.
CheckBox c;
for (int i = 0; i < 5; i++) {
c = new CheckBox();
c.ID = "Checkbox" + i.ToString();
divContainer.Controls.Add(c); //create a div with runat="Server" attribute or use an asp:Panel, etc. container controls.
}
}
After that, try clicking the button again, the state will be always be maintained.
You must set an ID for each dynamic control so that they can be synchronized across postbacks.
As I understand - there is no matter where to create controls in OnInit or OnLoad
(but some books suggests in onLoad), the matter is where to place them - if
you place through Controls.Add - it place them out of <form></form> so postback
does not takes control's states. after cretating a placeholder inside <form></form> and add dynamic controls to this placeholder everthing start to work fine.