Issues with Dynamically Loading a User Control - asp.net

I am dynamically loading a user control on the page which works fine. However i am facing one problem:
I have a class level variable on the User Control code-behind and the value to the same is assigned in User Control Page Load. Now when i click the button on my aspx page which contains the user control in it and try to call the User Control function from it, i see the value of the variable which i had set in the user control-page load has been reset.
The same code works perfectly if i have the user control at design time.
Code is something like this:
Page:
MyUserControl cntrl = Page.LoadControl("~/MyUserControl.ascx")
btn_click(){
{
cntrl.TestFunction();
}
User Control:
class MyUserControl: UserControl
{
//Variable
string org="";
Page_Load()
{
org="test";
}
TestFunction()
{
//The value of org variable is empty here.
//It should however be "test" which i have set in page_load
}
}

"Code is something like this:" - when providing code (even as fragments), try to make it to comply with the language syntax - in this case C#.
In order for MyUserControl.Page_Load to fire, you have to add the user control to the control tree of the page:
MyUserControl cntrl = (MyUserControl)Page.LoadControl("~/MyUserControl.ascx");
Panel1.Controls.Add(cntrl);
The Page_Load method must have very specific signature and scope:
class MyUserControl: UserControl
{
string org="";
protected void Page_Load(object sender, EventArgs e)
{
org="test";
}
}

Related

How a method located inside a user control can access data from aspx page?

I have a series of user controls of the same type on the same aspx page. When each user control loads, I want it to check some information in the aspx page, for instance, who is logged in, which session it is, and son on.
For now, I'm returning a hard-codded value. GetUserDBName() is located inside the user control
private string GetUserDBName()
{
return "UserDBName";
}
How does this method access data located in the aspx page that contains the user controls? And below is how the session is defined inside the aspx page.
private string strDBName = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
strDBName = Session["UserDBName"].Trim();
}
Thanks for helping
EDIT
The parent page's name is NewHireCheck.aspx. The user control's name is CheckListByDepartment.ascx.
The user control keeps a reference to the container page through the Page property.
So in your user control code you are allowed to do the below:
var resultFromPageMethod=((yourPageType)this.Page).APageMethod();

Property null after postback - Dynamically loaded control

I'm aware this question has been asked many times before but I suspect I have a unique scenario.
I'm loading a Child Control (ASCX) and setting a Property on that Control. This works perfectly fine until postback where the property is null.
Herewith the First Class which loads the ChildControl :
protected override void CreateChildControls()
{
MyUserControl control = (MyUserControl)Page.LoadControl(_ascxPath);
control.MyProperty = base.MyProperty
Controls.Add(control);
}
Then, on my Child Control I've got the following code:
public partial class MyUserControl : UserControl
{
public MyType MyProperty { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Exception on next line because Property is null (only on postback)
var somevalue = MyProperty.SubProperty;
Ok. Let me try to explain it.
1. Once page is created, you get full page lifecycle
2. You click on some control to create user control, and you get it
3. Now you are entering value to this control, and getting postback
4. On server side postback is handled, but as you can see viewstate actions appear as soon as page is loaded.
One of main purposes of viewstate is handling control events, to see if they are changed, or save their states or something else.
5. If on the moment, when viewstate is loaded you control is still not constructed, then all it's events and values would be ignored.
Solution either make it static control and just hide it, either create it before viewstate actions started.
You need to add the control and set properties in the Page_Init event, other wise you will lose the properties value.
In Microsoft explanations about ASP.NET page life cycle, it is written that dynamically created controls must be created in PreInit.
It worked for me.
Here is my main page :
protected global::System.Web.UI.HtmlControls.HtmlGenericControl FiltersZone;
(. . .)
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
FiltersZone.Controls.Add(new PlanningFiltersSurgeonWeb());
}
This dynamically created ".ascx" control contains an hidden field :
<input id="hidTxtPaint" type="hidden" name="hidTxtPaint" runat="server" />
I am now able to retrieve its value from within dynamically created ASCX control Page_Load event, after a "submit" or a "__dopostback('hidTxtPaint')" initiated from JavaScript.
On the other hand, the hidden field's value is always empty after a POST if its parent ".ascx" control is added in main page's Page_Load event.

User Control Page_Load event not reading variable passed from main page

I have problem passing a variable from a main page containing a user control to the user control itself. Although the passed variable is available generally in the code-behind of the user control the page_load event can't seem to read it.
My code -
In the main page code-behind:
protected void FindCCFsButton_Click(object sender, EventArgs e)
{
if (CustomerDropDown.SelectedIndex != 0)
{ SearchUcCCFList.SetCustID(CustomerDropDown.SelectedValue); }
}
(SearchUcCCFList is the instance of the user control in the main aspx page).
In the user control code behind:
public partial class ucCCFList : System.Web.UI.UserControl
{
public string srchCust { get; set; }
public void SetCustID(string custID)
{
srchCust = custID;
testCustLabel.Text = GetCustID(); //this works
}
public string GetCustID()
{
return srchCust;
}
protected void Page_Load(object sender, EventArgs e)
{
CCFGridView.DataSource = DAL.SearchCCFs(custID : GetCustID()); //doesn't work
CCFGridView.DataBind();
test2CustLabel.Text = GetCustID(); //doesn't work
}
In the Page_Load event GetCustId() doesn't return anything (so the records aren't filtered and all get returned) although it can be read in the methods outside the Page_Load.
I'm probably making a beginners error but any help would be appreciated.
Edit - following Alan's suggestion in the comments I stepped through the page loading sequence & it appears that the user control's Page_Load event is running BEFORE the code in the main page's button click so the variable is not yet available. The sequence after clicking the button is:
User control Page_Load runs
Code in button event on main page
Other code (outside Page_Load) in user control runs hence variable is available here.
This seems a bit weird, is there another way to pass the variable into the user controls Page_Load?
In this case, your click handling even on the main page is called after the user control page load call. Your variable is being set, but not until after your data binding in the user control.
Either switch the user control to declarative binding which will handle calling methods in the correct order for you. Or the easier fix in this case is to change the user control data binding from Page_Load to Page_PreRender, which is called later in the life cycle, after the main page click handling call.
protected void Page_PreRender(object sender, EventArgs e)
{
CCFGridView.DataSource = DAL.SearchCCFs(custID : GetCustID()); // will work now
CCFGridView.DataBind();
test2CustLabel.Text = GetCustID(); // will work now
}
For a more thorough answer, read up on the ASP.NET page life cycle including the interaction with user controls' life cycle.

ASP.NET UserControl Variable Lifeproblem

Got a Site.Master (Masterpage)
Got Default.aspx (Page)
And in the Default.aspx, there is a UserControl LoginUserControl.ascx placed
Now my problem:
In the LoginUserControl I check if Login is right.
If yes, then I set the Property IsLoggedIn on the Default.aspx to true:
//Inside LoginUserControl.ascx
if (/*Login is Ok*/)
{
((Default)Page).IsLoggedIn = true;
}
So, now I need this Information in my Masterpage Site.Master
I must know if User is logged in or not.. I do this:
//Inside Site.Master
protected void Page_Load(object sender, EventArgs e)
{
if (((Default)Page).IsLoggedIn)
{
//Do Something
}
}
But its ALWAYS false! Why? I thought I set the IsLoggedIn = true ?! Why is it then false? Is it a Lifecycle problem and what I must do, that it works :(
You should add the property IsLogged on to the viewstate of the page.
public bool IsLoggedOn {
get { return ViewState["IsLoggedOn"]==null?false:Convert.ToBoolean(ViewState["IsLoggedOn"]); }
set { ViewState["IsLoggedOn"] = value; }
}
Or if the property is used over multiple pages you should add it to the Session (replace ViewState with Session)
This is more that likely a page lifecycle issue. Page_Load in the Site.Master runs before Page_Load in your user control. What you will need to do is find the appropriate page and control events in which to apply your code.
This page has a complete breakdown of page/control/user control event life cycles and should help (scroll down to the merged events).
I think your best options are to either set IsLoggedIn property during the user controls Page_Init event or retrieve and act on it during the master page's Page_PreRender event.

ASP.Net CustomValidator in a CompositeControl

I present to you a little mystery... the following control is intended to fail validation every time, no matter what, but it does not:
public class Test : CompositeControl
{
protected override void CreateChildControls()
{
Controls.Clear();
CreateControlHierachy();
ClearChildViewState();
}
void CreateControlHierachy()
{
var validator = new CustomValidator
{
ErrorMessage = "Can't do that!"
};
validator.ServerValidate += (sender, e) =>
{
e.IsValid = false;
};
Controls.Add(validator);
}
}
To "fix" the issue, add the following line to CreateControlHierachyand all works as expected:
Controls.Add(new TextBox());
The control is registered in the web.config and placed on a simple page like this:
<uc:Test runat="server" />
Using the debugger on a post back event reveals the following:
The validator is in the control hierachy on the page, as expected.
The validator is not registered in Page.Validators.
Both Page.IsValid and validator.IsValid are still true.
What effect is the TextBox having on the validator and what is the correct way to fix this?
I found a possible explanation for this. The presence of the TextBox adds a child control to your control that is an IPostbackDataHandler. In order to load the post data the page must first find the control which of course it does by calling FindControl. As FindControl does its thing it eventually accesses the Controls collection of your control. Because your control is a CompositeControl this calls EnsureChildControls which call CreateChildControls.
All of this happens before Validation. Take out the TextBox and the Controls collection is no longer accessed before validation and therefore the validator is not created until after validation (most likely during prerender)
Since your validator doesn't exist at the validation stage it doesn't get called. I recommend adding a call to EnsureChildControls before validation occurs.
protected override void OnLoad(EventArgs e)
{
EnsureChildControls();
base.OnLoad(e);
}

Resources