Load Dynamic Control in Asp.net (Asp Page Lifecyle) - c#

I have a function to load a user control, it looks like this:
private void AddPopupControlToPage()
{
WidgetConfiguration popupControl = new WidgetConfiguration();
popupControl = (WidgetConfiguration)LoadControl("~/Docking/Widgets/WidgetConfiguration.ascx");
popupControl.ID = "PopupControlInput1";
g_PopupControlId = popupControl.ClientID;
popupControl.Attributes.Add("width", "150px");
Form.Controls.Add(popupControl);
}
I have drop down that allows me to change the page layout based on what template is selected. I should be able to press call the popup control from any template(page). Based on what I've read here http://msdn.microsoft.com/en-us/library/ms178472.aspx I should be able to load my control in the Page_PreInit event, however the form is not loaded at that point and I get a null reference error. Any ideas on how/where I should load my popup control and keep it available to any selected page?

you should load a control always overriding the CreateChildControls method
soomething like
protected override void CreateChildControls()
{
base.CreateChildControls();
//now load your control here
}

Related

Which event is fired when Content property is changed

I have two Pages ProductSearch,ProductDetail and Im changing the Content property to Navigate between Pages. I want to know if any events are fired so I can write some code in it?
On ProductDetail Page I have UIElement property
public UIElement MainContent { get; set; }
On ProductSearch Page I Navigate to ProductDetail By setting the Content property like this:
private void OnGetDetailsClick(object sender, RoutedEventArgs e)
{
ProductDetail productDetail = new ProductDetail();
productDetail.MainContent = this.Content;
this.Content = productDetail;
}
On ProductDetail Page's Back Button I navigate back to ProductSearch:
private void OnBackButtonClick(object sender, RoutedEventArgs e)
{
this.Content = MainContent;
}
Now I want to know how can I call a method when I navigate Back to ProductSearch Page i.e how would I know that I have Navigated from ProductDetail Page? I tried to check if it loads the page but found out that When you change content of control it doesn't fire the load event of the page. Any solution?
Yea this will not execute the load event since your are only changing the content obviously.
if you want to take advantage of navigation you should check out this video. Even if its done with blend the concepts apply also with Visual STudio: https://vimeo.com/6599527 (Simple Silverlight Master/Detail Navigation App with Blend 3)
You should check out articles on master detail binding like this one: https://msdn.microsoft.com/en-us/library/cc645060(v=vs.95).aspx
The key is to take advantage of the powerful binding concepts which come with silverlight. And if you are not using deep linking you might want to consider using a user control to hide/show details instead of a extra page.
HTH

Response.Redirect will Lost ViewState?

Suppose, on Page_Load() of a page (WebForms) that I create this Control :
HtmlGenericControl optionBox = new HtmlGenericControl("div");
optionBox.Attributes["class"] = "class_1";
Than, a use will recall the page using a LinkButton. On the method called from this button, I change the class of my previous div :
protected void cmdCerca_Click(object sender, EventArgs e)
{
...
div.Attributes.Add("class", "class_2");
...
}
Well, if I watch on the rendered result, I'll see that the class of the div have been changed.
This means that, in the next call to this page (from this context, example calling cmdCerca_2_Click), that object will be recovered from the View, getting class_2, not class_1.
But, this doesnt happens if, at the end of cmdCerca_Click, I call the same page with Response.Redirect(). Seems that the View will be lost.
Why? And how can I fix it?
Hope the question is clear.
You need to add the controls in the page init event, rather than load, in order to get them into the control tree.
You must be recreating this control on every postback? In this case, your default class will be set every time.

Load Server Control from Assembly and hook up events

I have several Server Controls, each in a separate assembly and I'd like to load one of them dynamically into a page depending on some choice. There seems to be a problem where the server side events in the control are not firing however.
e.g. Controls are of the form:
[ToolboxData("<{0}:MyPlugin runat=server></{0}:MyPlugin>")]
public class MyPlugin : WebControl, PluginSystem.Interface.IMyPlugins
{
protected override void RenderContents(HtmlTextWriter output)
{
...
_btn = new Button();
_btn.ID = "btnSave";
this.Controls.Add(_btn);
_btn.Click += new EventHandler(btn_Click);
_btn.RenderControl(output);
}
void btn_Click(object sender, EventArgs e)
{
//do something. This doesn't fire
}
}
The controls are loaded from their assemblies:
public static IMyPlugins GetPlugin(string assembly, string type)
{
var t = Type.GetType(type + ", " + assembly);
IMyPlugins rtn = (IMyPlugins)Activator.CreateInstance(t);
rtn.Initialise();
return rtn;
}
How do I inject the loaded assembly into a page so that the events in the control will fire? Is that possible?
Thanks for any help!
You're adding the controls way too late in the page lifecycle. Add the server side controls in the OnInit Page event is your best bet.
Check out this link for an overview of the lifecycle process. The controls need to be created by the time the postback event handling happens. This series is also really good.
Dynamically changing the page based on user choice can be a pain in the ass because of this. There are a few options to go with. The easiest way is to add all your controls in the OnInit and then remove them when you know the selection the user made.
If it's truly completely dynamic, and you have no idea what control you are going to render until after the postbacks have been handled, it can be easier to step away from ASP.NET's viewstate/postback system and check things yourself. You can always get the full range of post values at any time in the page lifecycle by checking the Form.Request collection.

Asp.NET custom server control event handler not firing on second postback

I'm developing a custom server control in Asp.NET (.NET 3.5) which inherits the CompositeControl class. Inside my control I'm overriding the CreateChildControls() method to generate a mixture of html and Asp.NET server controls. Some of the Asp.NET controls which are added are LinkButtons (which each have their Command event handler set to a method within my control). What I'm finding is that the first time one of these LinkButtons is clicked a postback is triggered and the event handler method is correctly fired. Inside this event handler method CreateChildControls() is explicitly called to regenerate the control in response to the postback. What I then find is that subsequent clicks of the LinkButtons postbacks fail to raise the event handler method.
I assume that the way I'm handling the regeneration of the control on postback must be at fault, but I can't figure out what to do - I am aware of the fact that on that first postback CreateChildControls() is called twice which probably isn't ideal but since CreateChildControls is called before any events are raised, I don't see a way around this.
A simplified version of my control class is shown below:
public class SearchResults : CompositeControl
{
private int PageIndex = 0;
protected override void CreateChildControls()
{
//do stuff here e.g.
LinkButton prevLink = new LinkButton();
prevLink.Text = "< Prev";
prevLink.CommandArgument = (PageIndex - 1).ToString();
prevLink.Command += new CommandEventHandler(PagerLinkCommand);
this.Controls.Add(prevLink);
}
protected void PagerLinkCommand(object sender, CommandEventArgs e)
{
PageIndex = int.Parse(e.CommandArgument.ToString());
CreateChildControls();
}
}
EDIT
The problem here was caused by the fact that the control is used in a Sitecore site and I had forgotten to register the control type in the web.config file with a <typesThatShouldNotBeExpanded> entry. This entry is used to prevent server controls from having their events messed up by Sitecore - this can cause similar problems for standard server controls such as ListView, GridView and Repeater etc. My web.config was modified as shown below:
<typesThatShouldNotBeExpanded>
<type>System.Web.UI.WebControls.Repeater</type>
<type>System.Web.UI.WebControls.DataList</type>
<type>System.Web.UI.WebControls.GridView</type>
<type>MyNamespace.MyCustomControl</type> <!-- This is the bit I added -->
</typesThatShouldNotBeExpanded>
In my experience this sort of problem is usually due to not assigning an ID to dynamically generated controls.
LinkButton prevLink = new LinkButton();
prevLink.ID = "prevLink";
Apologies... this is not a complete answer, but a debugging suggestion that is too long for a comment:
In your browser save an HTML copy of your page for initial load, postback load, and second postback. Then compare the files using your favorite comparison tool. Eliminate obvious differences like search results, etc. This can help you pinpoint any issues with control IDs, missing controls, etc.
The two absolute keys to successful dynamically created controls are
1) Creating them at the correct time during the page lifecycle
2) Re-creating the EXACT SAME control hierarchy (including IDs) on postback
To get the proper control tree override the Controls property and call the EnsureChildControls, and also call the EnsureChildControls and not the CreateChildControls inside the PagerLinkCommand.
/// <summary>
/// Gets controls.
/// </summary>
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return base.Controls;
}
}
/// <summary>
/// Create child controls.
/// </summary>
protected override void CreateChildControls()
{
this.Controls.Clear();
//do stuff here e.g.
LinkButton prevLink = new LinkButton();
prevLink.Text = "< Prev";
prevLink.CommandArgument = (PageIndex - 1).ToString();
prevLink.Command += new CommandEventHandler(PagerLinkCommand);
this.Controls.Add(prevLink);
}
protected void PagerLinkCommand(object sender, CommandEventArgs e)
{
PageIndex = int.Parse(e.CommandArgument.ToString());
EnsureChildControls();
}
The reason for this behaviour was not down to the server control itself, but was Sitecore-related. In order for Sitecore to not interfere with server control postbacks, it is necessary to add an entry under the typesThatShouldNotBeExpanded section in the web.config file as shown below.
<typesThatShouldNotBeExpanded>
<type>System.Web.UI.WebControls.Repeater</type>
<type>System.Web.UI.WebControls.DataList</type>
<type>System.Web.UI.WebControls.GridView</type>
<type>MyNamespace.MyCustomControl</type> <!-- This is the bit I added -->
</typesThatShouldNotBeExpanded>

ASP.NET PopupControlExtender Problem

I am trying to create a popup which will be used to select a month/year for a textbox. I have kind of got it working but however when I try and read from the textbox when I Submit the form it returns an empty string. However visually on the page I can see the result in there when I click the Done button which can be seen in the screenshot.
http://i27.tinypic.com/2eduttx.png - is a screenshot of the popup
I have wrapped the whole textbox/popup inside a Web User Control
Here is the code of the control
Code Behind
ASP Page
and then read from the Textbox on the button click event with the following
((TextBox)puymcStartDate.FindControl("txtDate")).Text
Any suggestions of how to fix the problem?
You may need to read the form posted value rather than the value from the view state. I have the following methods in my code to handle this.
The below code just grabs the values in the request headers (on post back) and sets/updates the controls. The problem is that when using the ASP.NET Ajax controls, it doesn't register an update on the control, so the viewstate isn't modified (I think). Anyways, this works for me.
protected void btnDone_Click(object sender, EventArgs e)
{
LoadPostBackData();
// do your other stuff
}
// loads the values posted to the page via form postback to the actual controls
private void LoadPostBackData()
{
LoadPostBackDataItem(this.txtYear);
LoadPostBackDataItem(this.txtDate);
// put other items here if needed
}
// loads the values posted to the page via form postback to the actual controls
private void LoadPostBackDataItem(TextBox control)
{
string controlId = control.ClientID.Replace("_", "$");
string postedValue = Request.Params[controlId];
if (!string.IsNullOrEmpty(postedValue))
{
control.Text = postedValue;
}
else
{
control.Text = null; // string.Empty;
}
}

Categories