Programmatically adding a user control in ASP.NET - c#

I have a user control that needs to load a child control when a button is clicked.
The trouble is that it has to request the control from another class.
So in the button click event, I call the function to get me my control, and add it to the page, like this:
UserControl ctrl = ExampleDataProvider.GetControl(some params...);
myDetailPane.Controls.Add(ctrl);
The GetControl method looks like:
public static UserControl GetControl(some params...)
{
ExampleDetailPane ctrl = new ExampleDetailPane();
ctrl.Value = "12";
ctrl.Comment = string.Empty;
return ctrl;
}
This isn't working due to the page's lifecycle - the Page_Load of the child control gets fired and its controls are null.
I kind-of know that my approach is wrong and why, but don't know the best way to go about fixing it! Could anyone help?

Dynamic controls must be re-created on every postback, this Article is a good link about how to persist dynamic controls and their state.

If you want to access your control in PostBack or you want to bind Event, you have to create them in CreateChildControls() method.
private UserControl _uc = null;
/// <summary>
/// Creates all controls.
/// </summary>
/// <remarks>All the controls must be created in this method for the event handler</remarks>
protected override void CreateChildControls()
{
_uc = new UserControl ();
this.Controls.Add(_uc);
base.CreateChildControls();
}

Create your control in Page_Init. Then make it visible on your Button_Click event.
(CTRL+C/CTRL+V from some other question I answered last week):
Everything that has to be maintained between page cycles should be declared in Page_Init, not Page_Load.
All the initialization, like adding event handlers, and adding controls should be added during initialization, as the state is saved between page cycles. Handling with the content of controls and the viewstate, should be done in Load.
Check also http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Init
Raised after all controls have been initialized and any skin
settings have been applied. Use this
event to read or initialize control
properties.
.
Load
The Page calls the OnLoad event method
on the Page, then recursively does the
same for each child control, which
does the same for each of its child
controls until the page and all
controls are loaded.
Use the OnLoad event method to set
properties in controls and establish
database connections.

Two possible approaches:
Have the control in the page but not loaded with anything until they click their button. Then you can populate the values in the control. This has the benefit of being within the page life cycle. Note, you can always use the "display: none" style setting for the that your user control is in. Then, as part of the OnClick for the button, you can reveal the div making your control visible.
You could pop up another window, though obviously this has the potential for being blocked by popup blockers.

Related

Event that fires when a control gets added onto another control

Is there an event that gets fired when a user control gets added onto a Form?
I need this to get the size of the Parent control of the user control.
But when the user control gets initialized etc, the Parent = null.
Because the user control hasn't been added yet onto the Form. So i can't get the Parent control (which is the Form) at this point.
So i'll have to do the re-sizing of the user control afterwards.
There is a ParentChanged event that all Controls inherit. In the event handler method you can inspect the Parent property, which will be set to the new parent at that point.
You can try using the Control.ParentChanged event. This will fire whenever the parent of the control is changed, so you can check if the parent is the form and then continue with how you want to react.
Alternatively, you can use the Control.ControlAdded event.
You have the ControlAdded event on the form, wich is initialized in your InitializeComponent(). Most of the time this event is duely placed after the adding of components. If you place it before the adding of UserControls to the form you will fire events each time you add a component.
I would recommend adding the usercontrol you need such specific control over in your codebehind and not move the eventhandler.
If you do that you can add a parent to your usercontrol which might give you the information you need.
var textBox = new TextBox {Parent = this};

Loading ASP.NET user control at run time

I have an ASP.NET user control with a button, and I want to add it to the page when the user clicks a button from another user control. I have created an event handler to the first user control to handle it from the page and add the second user control to a page. Everything is working normally, but the button on the second user control doesn't respond to the event.
I place the second control on RadAjaxPanel
Note: When I add the second user control at design time its working fine.
All dynamically created controls should be added by the end of Page_Init (though sometimes you can get away with them added by the end of Page_Load).
If you're only adding them based on a button click event then you've done this in the event handers which fire AFTER Page_Init and Page_Load in the lifecycle - This is why your events don't fire and why it works fine when you add at design time.
This is because when a button is clicked on the second user control - the whole page lifecycle starts again. The page goes through Page_Load and Page_Init first and your control doesn't get loaded here. So, when the page lifecycle handles the "handle postback events" part, the control no longer actually exists, so the event doesn't fire.
Conversely, when you add at design time, the control exists in Page_Init and Page_Load so is able to handle the postback events from the user control because it already exists in the control tree - if this makes sense.
You need to think how you can restructure so they're added by the time Page_Load has finished at the very latest or it won't work. Without code samples or more detail it's hard to suggest exactly how you might do this. One possibility would be to set it visible instead of loading it outright - but if the control does some 'heavy lifting' on load like database hits or API calls then this might not be suitable for you.
I did something similar. What I did was to load some controls dynamically based on a selection from a DropDownList. If you have a method which loads the control for you, let's call it LoadControls(), then you can do something like this:
DropDownList_Click {
ViewState("LoadControls") = true;
LoadControls()
}
By setting the ViewState variable, you can then indicate Page_Load to load the controls on future postbacks:
Page_Load {
if (ViewState("LoadControls") == "true")
{
LoadControls();
}
}
This has the effect of then loading the control on-the-fly when the event first happens, and then at future times in the lifecycle.

UpdatePanel's PostbackTrigger that is inside a usercontrol inside a masterpage?

I have a masterpage and inside that masterage is a user control that has a toolbar with a save button. I then have an aspx page that inherits form t he master page. In that page I have and updatepanel. Is it possible to set the post back trigger to the Save button inside the usercontrol?
You should be able to use Master.FindControl("MySaveButton") from within the content page, and attach it to the scriptmanager's trigger list:
this.MyScriptManager.RegisterAsynchPostBackControl(Master.FindControl("MySaveButton"))
Unless I'm not understanding the question correctly.
Check the fourth post down (marked as answer) here, it ought to help.
In short, create an PostBackTrigger instance, set fields appropriately and then add to the UpdatePanel's Triggers collection.
For example (from linked site):
//Creates a new async trigger
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
//Sets the control that will trigger a post-back on the UpdatePanel
trigger.ControlID = "btnCommit";
//Sets the event name of the control
trigger.EventName = "Click";
//Adds the trigger to the UpdatePanels' triggers collection
pnlMain.Triggers.Add(trigger);
I went with a different approach of find my controls. I used this method. I have used this in the past and not sure why I didn't think about it earlier. In my user control I expose controls as properties. In my master page I created a property that allows me to get the user control instance. In my page I can call this: Master.UserControlName.PropertyInControl
So, if I expose a button or control in the user control, I should be able to add that to the trigger collection.

ASP.NET usercontrol: check if usercontrol is visible

My question is somewhat related to this thread: How to avoid Initialization of web user control inside aspx?
The UserControl should only be visible when a button is clicked.
So my usercontrol is set like this:
<example:usercontrol ID="idControl" runat="server" Visible="false" />
<asp:Button ID="showMyControl" runat="server" OnClick="ShowMyControl" /
And the usercontrol itself checks if he's visible:
protected void Page_Load( object sender, EventArgs e ) {
// only execute if the user control is visible
if ( this.Visible ) {
...
}
}
When I click the button I'm setting the property Visible of the usercontrol to true but when the postback occurs the Visible-property in the Page_Load of the usercontrol is still set to false.
My UserControl is probably loaded first and the Visible-property is set afterwards?
Is there an easy way to resolve this?
Thanks in advance!
The Load event of your control, which is being handled by your Page_Load event handler method if I understand correctly, gets fired before the Click event of your button control. Therefore, when the Page_Load method checks this.Visible, the property has not yet been changed because the Click event handler has not yet executed.
For this reason, I think that checking the Visible property of your control would be more appropriate in the PreRender event instead of the Load event.
I'm guessing that you're doing some sort of data retrieval or something that you wish to avoid if the control is not visible. Unfortunately, this sort of issue regarding the page life-cycle and the order in which events fire is sort of a common issue to deal with in ASP.Net programming.
If all of your initialization code can easily be moved into the PreRender event, then great. Problem solved (hopefully). If not (i.e. you need something to happen before the PreRender), you may need to come up with some other mechanism to ensure that your code executes at the right time. For example, you could expose a "SetVisible" method on your control which sets the Visible property to true and then also executes whatever initialization logic is needed. The downside of this is that you can't really guarantee that some code won't just set your control's Visible property to true outside of the SetVisible method that you provide.
Another idea is to actually override the Visible property and perform your initialization logic whenever that property gets set to true.
Put the code which you call in the Control's Page_Load event into the PostBack event. Make sure the button has autopostback set to true.
What you are looking for is the Control.EnsureChildControls method. This method exists for this very situation. It will ensure that all child controls have been created. Then you can set your visible property.

.net Page events firing order changing

Ok this is a really annoying bug that I have been having issues with all morning!.
I have a custom control that we have used on many project that has properties that are set and stored in Viewstate by the calling pages onload. the control sets up childcontrols with propertes on the CreateChildControls() method of the custom control.
Normally as usual on a postback the Page_Load event is fired then the CreateChildControls method of the control on the page is fired.
The strange thin though is we have a login system (custom membership provider) on the site and when a user is logged in the opposite happens first the CreateChildControls() method fires then the Page_Load so the control properties are wrong (set from the previous postback)
How could the events be firing in a different order? I thought all page events happened in the same order no matter what and I don't see how being logged in would change that order.
UPDATE: It seems the issue is I'm not calling EnsureChildControls() but I'm not sure where it should be called? If several properies are set on the control which are used in setting up the child controls when should I call EnsureChildControls(), I guess I don't fully understand what EnsureChildControls() does?
CreateChildControls is called whenever the ASP.NET page needs them. There is no specific point in the page cycle for that. It can happen in the Init event, it can happen in the Load event. If you want to make sure your child controls are available, then call EnsureChildControls() method of your control. You can do that in the control's Init event to make sure you have child controls through the whole lifecycle or you can do it whenever you need a reference to one of the child controls - e.g. in the getter/setter of a property of your control.
When creating properties of a server/user control that need access to contained child controls I use the following:
public Whatever SomeProperty
{
get
{
EnsureChildControls();
<more code here>
}
set
{
EnsureChildControls();
<more code here>
}
}
This ensures your control consumers are free to work with your control at various stages of the page lifecycle.

Categories