Dynamically load user controls on button click, postback issue - c#

I'm trying to load usercontrols on button click, but problem is that, it disappears on postback inside user control.
this is how i load controls:
private bool IsUserControl
{
get
{
if (ViewState["IsUserControl"] != null)
{
return (bool)ViewState["IsUserControl"];
}
else
{
return false;
}
}
set
{
ViewState["IsUserControl"] = value;
}
}
#region Usercontrols
private void CreateUserControlAllNews()
{
Control featuredProduct = Page.LoadControl("path/usercontrol.ascx");
plh1.Controls.Add(featuredProduct);
}
#endregion
protected void allNewsbtn_Click(object sender, EventArgs e)
{
this.IsUserControl = true;
if(IsUserControl)
CreateUserControlAllNews();
}

You need to reload the control when the page is post back. For example,
protected void Page_Load(object sender, EventArgs e)
{
if (IsUserControl)
{
CreateUserControlAllNews();
}
}
private void CreateUserControlAllNews()
{
Control featuredProduct = Page.LoadControl("path/usercontrol.ascx");
featuredProduct.ID = "1234";
plh1.Controls.Add(featuredProduct);
}

OF course it disappears, every request creates a brand new instance of your page and if you dont re-create the control on that postback then it wont exist.
See the following links about this very common issue.
Singing eels
Another SO question

Related

Link click overriding in a webBrowser control

I am using Virtual Studio Community in C# (.Net 4.5).
I have a simple form, which contains one button and one webBrowser control.
When I click the button, I make the webBrowser navigate to google.com.
Then, when the page is loaded, I try to override the linkClick events as I saw in a solution I read on this site (stackoverflow) earlier.
But then, when I click on a link on the loaded page, it says the navigation was cancelled, but it navigates anyways.
What am I doing wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("http://www.google.com/");
}
private bool bCancel = false;
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
for (int i = 0; i < webBrowser1.Document.Links.Count; i++)
{
webBrowser1.Document.Links[i].Click += new HtmlElementEventHandler(this.LinkClick);
}
}
private void LinkClick(object sender, System.EventArgs e)
{
bCancel = true;
MessageBox.Show("Link Was Clicked Navigation was Cancelled");
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (bCancel == true)
{
e.Cancel = true;
bCancel = false;
}
}
}
You need to bind the WebBrowserControl.Navigating event to the handler you've written; having the handler's name matching the control underscore event name isn't enough.
So you can do this in the Form1's constructor:
public Form1()
{
InitializeComponent();
webBrowser1.Navigating += new WebBrowserNavigatingEventHandler(webBrowser1_Navigating);
}
Better yet, add a Load event and do the same there. Check out the official documentation on the subject.

What are techniques in ASP for communication from usercontrol to parent page?

I have having some trouble with communication from a usercontrol to the main page. The order in which events are raised means that the action on the user control occurs too late in the post back to have an effect on the main page.
For example, I have a button on a user control which, when pressed, raises a custom event that is being listened for on the main page. When the button is pressed the postback order is:
page_load - on the main page
page_load - on the usercontrol (the user control is loaded programitically by the main page page_load)
The button call back on the user control
The event call back method on the main page
By this point, it seems it is too late for anything the event call back method does to have any effect on the rendered page, for example I am trying to use it to change the usercontrol that is being displayed.
What other techniques can be used for this kind of communication?
Relevant code
Main page:
public string LastLoadedControl
{
get
{
return Session["LastLoaded"] as string;
}
set
{
Session["LastLoaded"] = value;
}
}
private void LoadUserControl()
{
string controlPath = LastLoadedControl;
ContentPlaceholder.Controls.Clear();
if (string.IsNullOrEmpty(controlPath))
controlPath = Utils.Paths.USERCTRL_BASE + "Main.ascx";
Control uc = Page.LoadControl(controlPath);
ContentPlaceholder.Controls.Add(uc);
}
protected void Page_Load(object sender, EventArgs e)
{
LoadUserControl();
if (!IsPostBack)
Utils.Events.redirectPage += Events_redirectPage;
}
private void Events_redirectPage(string path)
{
if (path.Equals("Main"))
{
//Session.Clear();
//Session.Abandon();
}
else LastLoadedControl = Paths.USERCTRL_BASE + path + ".ascx"
LoadUserControl();
}
User control
protected void profileBtn_Click(object sender, EventArgs e)
{
Utils.Events.triggerRedirectPage("Login");
}
Event
public class Events
{
public delegate void redirectEvent(string path);
public static event redirectEvent redirectPage;
public static void triggerRedirectPage(String path)
{
if (Utils.Events.redirectPage != null)
Utils.Events.redirectPage(path);
}
}
There are two approaches that you can follow.
Approach 1:
public interface IEventProvider
{
void TriggerEvent();
}
public class YourPage: Page, IEventProvider
{
// Other page methods
public void TriggerEvent()
{
// Your Implementation
}
}
public class YourUserControl : WebUserControl
{
protected void profileBtn_Click(object sender, EventArgs e)
{
IEventProvider eventProvider = this.Page as IEventProvider;
if(eventProvider != null)
eventProvider.TriggerEvent();
}
}
Approach 2:
public interface IEventProvider
{
// This does not have to be a boolean. You can use a string / enum / anything that suits your implementation
bool Trigger {get; set;}
}
public class YourPage: Page, IEventProvider
{
// Other page methods
protected override void OnLoadComplete(EventArgs e)
{
// This will be raised when all the events have fired for all the controls in the page.
if(this.Trigger)
TriggerEvent();
}
protected void TriggerEvent()
{
// Your code here
}
public bool Trigger
{
get;
set;
}
}
public class YourUserControl : WebUserControl
{
protected void profileBtn_Click(object sender, EventArgs e)
{
IEventProvider eventProvider = this.Page as IEventProvider;
if(eventProvider != null)
eventProvider.Trigger = true;
}
}

Ensure page is accessed from a specific link

Say if I have link1.aspx and link2.aspx. Within link1.aspx, I redirect the user to link2.aspx.
What is the most efficient way of checking that link2.aspx is only accessed via link1.aspx?
For example, something like:
link2.aspx:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if page is not accessed via link1.aspx
{
Response.Redirect("~/portal.aspx");
}
}
}
I could use a query string but are there any other ways?
You can use UrlReferrer. However, it is not a secure way of detecting where the user comes from.
For example,
if (string.Equals(Request.UrlReferrer.AbsoluteUri,
"YOUR_REFERRER_URL",
StringComparison.InvariantCultureIgnoreCase))
{
}
If it is redirecting between pages inside your application, I would like to suggest to use SessionState which is more secure and robust than UrlReferrer.
link1.aspx.cs
private bool IsValidUrl
{
set { Session["IsValidUrl"] = true; }
}
protected void Button1_Click(object sender, EventArgs e)
{
IsValidUrl = true;
Response.Redirect("link2.aspx");
}
link2.aspx.cs
private bool IsValidUrl
{
get
{
if (Session["IsValidUrl"] != null)
return Convert.ToBoolean(Session["IsValidUrl"]);
return false;
}
set { Session["IsValidUrl"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsValidUrl)
{
// user comes from valid url.
// .... Do somthing
// Reset session state value
IsValidUrl = false;
}
}
You could use the Request.UrlReferrer property to check what page the user is coming from.

Event Handler is Always null

I have searched extensively on this, but cannot find the solution to my problem. I am trying to call a function in the code behind of a page from a user control on that page.
I have a web application that uses a master page. I am adding a user control that I wrote to one of the content pages. I added the user control to the aspx page by dragging and dropping it from the toolbox. I am able to see the user control from the code behind, but I cannot access the public functions. To fix that problem, I created an object of the user control in the code behind and used the LoadControl function. All of that seems to work fine.
The problem I am having is when I am trying to hook the into the EventHandler from the aspx page to the user control. Everything compiles and runs just fine, but I am not seeing anything happen on the page. I think the issue is that the EventHandler is always null.
User Control Code
public partial class ucBuyerList : System.Web.UI.UserControl
{
public delegate void BuyerSelectedEventHandler(object sender, EventArgs e);
public event BuyerSelectedEventHandler BuyerSelected;
private string name = "";
public string Name
{
get { return name; }
set { name = value; }
}
private string auid = "";
public string AUID
{
get { return auid; }
set { auid = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
private void OnBuyerSelected(EventArgs e)
{
if (BuyerSelected != null)
{
BuyerSelected(this, new EventArgs());
}
}
protected void lbBuyerList_SelectedIndexChanged(object sender, EventArgs e)
{
SetNameAndAUID();
OnBuyerSelected(e);
}
private void SetNameAndAUID()
{
name = lbBuyerList.SelectedItem.Text;
auid = lbBuyerList.SelectedItem.Value;
}
}
Parent Page Code
public partial class frmBuyerInformation : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Master.changePageTitle("Buyer Information");
buyerList.BuyerSelected += new ucBuyerList.BuyerSelectedEventHandler(buyerListControl_BuyerSelected);
}
void buyerListControl_BuyerSelected(object sender, EventArgs e)
{
DisplayBuyerInformation();
}
public void DisplayBuyerInformation()
{
tbName.Text = buyerList.Name;
tbAUID.Text = buyerList.AUID;
}
}
Can anyone see what I am doing wrong?
EDIT: This issue has been resolved. The code snippits above are now functional. If anyone runs into the issue I had, you can model the code above. Make sure that AutoEventWireup="true" in both the aspx and ascx pages. Thank you June Paik for your solution. Thank you Diego De Vita for your input as well.
I've been struggling with events for quite a while as well. Nowadays I always create them this way 'cause it's the only way I know it works. Haven't tested it with your code but here it goes anyway:
public partial class ucBuyerList : System.Web.UI.UserControl
{
public delegate void BuyerSelectedEventHandler(object sender, EventArgs e);
public event BuyerSelectedEventHandler BuyerSelected;
public string Name;
public string AUID;
protected void Page_Load(object sender, EventArgs e)
{
//Select the first buyer in the list when the user control loads
if (!IsPostBack)
{
lbBuyerList.SelectedIndex = 0;
}
}
private void OnBuyerSelected(EventArgs e)
{
BuyerSelectedEventHandler handler = BuyerSelected;
if (handler != null)
{
handler(this, new EventArgs());
}
}
protected void lbBuyerList_SelectedIndexChanged(object sender, EventArgs e)
{
Name = lbBuyerList.SelectedItem.Text;
AUID = lbBuyerList.SelectedItem.Value;
OnBuyerSelected(e);
}
}
In the parent page you can just call your function the same way you're doing it already.
It could be that Page_Load is too late in the page lifecycle to be using LoadControl and subscribing to the event. What happens if you move that code to the Page_Init method?

Updating parent page from dynamically loaded user control

Hosting page:
protected void Page_Load(object sender, EventArgs e)
{
LoadMyControl(Parameters); //Do it every page load to preserve it's state
}
protected void LoadMyControl(string parameters)
{
plchld.Controls.Clear();
Control userControl = LoadControl("TheUserControl.ascx");
userControl.ID = "userControl1";
plchld.Controls.Add(userControl);
}
Now inside this control, when a button is clicked I want to update ,let's say a Label on the hosting page.
What is the best way to do it? Custom event?
Solution maybe:
In the parent page add:
public Label Actions
{
get { return _Actions; }
set { _Actions = value; }
}
on User Control add the following to the top
<%# Reference Page="../parentpage.aspx" %>
and to change the value just do the following in the user control
ASP.parentpage cc = (ASP.parentpage)this.Parent.Page;
cc.Actions.Text = "hello world";
A UserControl has a Page property which is a reference to the page in which the control is added. You could either cast directly to the known page type that contains the label,
e.g.
protected void Button1_Click(object sender, EventArgs e)
{
var page = Page as _Default;
if (page != null)
{
page.Label1.Text = "Hello World";
}
}
but what would probably be better, is that you decorate you pages where this control can be used with an interface:
public interface ILabelHost
{
void SetLabel(string text);
}
public class _Default : System.Web.UI.Page, ILabelHost
{
...
That way you can use that same logic from before, but on anypage the control is loaded and implements the correct interface:
protected void Button1_Click(object sender, EventArgs e)
{
var host = Page as ILabelHost;
if (host != null)
{
host.SetLabel("Hello World");
}
}

Categories