Referencing User Control on separate .aspx page - c#

I have a .ASPX page that pulls in a user control from a master page, and I am trying to call an update() method in one user control (hereby referred to as control1), to an update panel that is in another user control (hereby referred to as control2).
I have set a reference to control2 in the .ascx page of control1:
<%# Reference Control="~/controls/MobileMenu.ascx" %>
I have instanced control2 and am trying to call the public method from the code-behind of control1:
controls_MobileMenu mobi = new controls_MobileMenu();
mobi.Update(ThisCustomer);
Here is the method that fires in control2:
public void Update(Customer customer)
{
getItemNums(customer);
}
protected void getItemNums(Customer customer)
{
int numItems = ShoppingCart.NumItems(customer.CustomerID, CartTypeEnum.WishCart);
if (numItems > 0)
{
lbwishlist.ForeColor = Color.Red;
lbwishlist.Text = "My Wishlist ( " + numItems + " )";
}
else
{
lbwishlist.ForeColor = Color.White;
lbwishlist.Text = "My Wishlist";
}
}
When my code runs though, and I step through it, my lbwishlist linkbutton is null and the code throws a null reference exception. Can anyone explain why this is considered null when the other control calls it? And is there any way around this?

Related

How to change text in Root.master on an event?

I have a project in VS 2013 with master page. In the Root.master I have the "Log In" which redirects me to the login page.
Log In
When I login I'm redirected to a certain page, let's say it Default.aspx.
In Default.aspx.cs I have:
if (Session["username"] == null)
{
Response.Redirect("Logare.aspx");
}
else
{
loginLink.Text ="Welcome, "+ Session["username"];
}
How could I do so when I'm logged in the text from Root.master to change from "Log In" to "Welcome, username"? I tried to get the loginLink id from Root.master but it's not known in Default.aspx.cs.
UPDATE
This is how "Log In" from Root.master is now:
<asp:Label ID="Label8" runat="server" Text="Log In"></asp:Label>
In Default.aspx.cs I have now:
if (Session["username"] == null)
{
Response.Redirect("Logare.aspx");
}
else
{
Label mpLabel = new Label();
mpLabel = (Label)Master.FindControl("Label8"); mpLabel.Text = "Welcome, " + Session["username"];
}
But, with this, I'm getting an error
Object reference not set to an instance of an object.
at mpLabel.Text = "Welcome, " + Session["username"];
So if I understood your question correctly, this is just about accessing control declared on the master page from within the content page code behind. You have two options to achieve that.
FindControl
Code is simple (borrowed from OP's own comment):
Label mpLabel = (Label) Master.FindControl("loginLink");
However be aware that FindControl works only with immediate children of the control. So if your structure looks like
MasterPage
Control1
Control2
loginLink
You will need to something like this:
Control c1 = Master.FindControl("Control1");
Control c2 = c1.FindControl("Control2");
Label mpLabel = (Label) c2.FindControl("loginLink");
Alternatively you can use recursive version of FindControl . It is not available out of the box, but many (really many) versions are on the web already. Here is one.
Expose controls via Master's interface
In your master page code behind define a property like that:
public Label LoginLabel
{
get { return this.loginLabel; }
}
And on the content page just use it. Don't forget to cast master to your specific type:
Label loginLabel = ((YourMasterPageClass)Master).LoginLabel;
That might not be particularly safe, so you can expose just label text instead:
public Label LoginLabelText
{
get { return this.loginLabel.Text; }
set { this.loginLabel.Text = value; }
}
((YourMasterPageClass)Master).LoginLabelText = "Welcome!";

Dynamically change MasterPage and ContentPlaceHolderID of asp content tag?

I have a page which initially inherited from MastePage.master . And I want to use the same page but with different masterpage(MasterPage2.master) at some other place in my project. For that I am using the following code.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
Content con = new Content();
con = (Content)this.FindControl("Content1");
this.Content1.ContentPlaceHolderID = "ContentPlaceHolder2";
}
}
I am also trying to set the asp content tag's ContentPlaceHolderID to ContentPlaceHolder2 which is from MasterPage2.master. Initially it was ContentPlaceHolder1.
But I am getting null value at con = (Content)this.FindControl("Content1");
Thanks
Page internally stores in private '_contentTemplateCollection' hashtable. it uses ContentPlaceHolderID property as key and stores special class (that will be used to build/initialize Content tag) as a value
- so to change ContentPlaceHolderID value (defined within markup) you need to modify this hashtable, remove old entry linked with old Id and add other entry with new Id
- you need to change ContentPlaceHolderId before creating master page otherwise an exception will be thrown in runtime
- best place to change Ids is Page 'preinit' event and if it is better to change Ids before change master page (if you will change master page at runtime)
To change ContentPlaceHolderID of Content tag, you can use following function in Page PreInit event
public static void AssignContentToNewPlaceHoldersWithinPage(Page pPage, string pOldId, string pNewId)
{
if (pPage == null || string.IsNullOrEmpty(pOldId) || string.IsNullOrEmpty(pNewId))
{
return;
}
// Try to get a reference to private hashtable using fasterflect free reflection library in codeplex (http://fasterflect.codeplex.com/)
// you can replace following line with standard reflection APIs
var lTmpObj = pPage.TryGetFieldValue("_contentTemplateCollection");
if (lTmpObj != null && lTmpObj is Hashtable)
{
var _contentTemplateCollection = lTmpObj as Hashtable;
if (_contentTemplateCollection.ContainsKey(pOldId) && !_contentTemplateCollection.ContainsKey(pNewId))
{
var lTemplate = _contentTemplateCollection[pOldId];
_contentTemplateCollection.Add(pNewId, lTemplate);
_contentTemplateCollection.Remove(pOldId);
}
}
}
function parameter are
pPage is reference to page instance contains content tag
pOldId is ContentPlaceHolderId property value in markup - the Id you want to change
pNewId is the new Id you want to use
I hope that my answer will be useful and I am sorry if my English language is not good
You can dynamically change the Master Page at runtime, but you need to use the same ContentPlaceHolder IDs. That way, your pages will work with either Master Page without adding extra code to change the IDs at runtime.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
}
}
You can even test that your page will work with either Master Page in the Visual Studio design/markup view by changing the MasterPageFile in the <% Page %> directive in the .aspx markup.
The Master Page can be changed by overriding OnPreInit.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = "~/MasterPages/MyOther.Master";
}
But for the ContentPlaceHolders I would suggest to create new ContentPlaceHolders with the same name in both of your MasterPages.

How call GetWebResourceUrl() when Page is null ?

I built custom ASP.NET control and it's working fine when I add it manually (drag and drop) or by code to controls in markup.
The custom control, MsgBox, had resources like JavaScript, CSS and images embedded in and the problem appeared when I tried to Render the control in class to return its HTML code, the Page instance is null and the "GetWebResourceUrl" needs it:
Page.ClientScript.GetWebResourceUrl(.....)
is there any way to get the resourceurl ? Here is my render code:
protected override void RenderContents(HtmlTextWriter writer)
{
using (PlaceHolder plh = new PlaceHolder())
{
if (Page != null)
{
if (DesignMode || Page.Header == null)
RegisterCSSInclude(plh);
}
HtmlGenericControl container = new HtmlGenericControl("div");
container.EnableViewState = false;
container.InnerHtml = "Control html code";
plh.Controls.Add(container);
plh.RenderControl(writer);
}
}
RegisterCSSInclude is method to register my css files:
private void RegisterCSSInclude(Control target)
{
// CSS
bool linkIncluded = false;
foreach (Control c in target.Controls)
{
if (c.ID == "MsgBxStyle")
{
linkIncluded = true;
}
}
if (!linkIncluded)
{
HtmlGenericControl globalCsslink = new HtmlGenericControl("link");
globalCsslink.ID = "MsgBxGStyle";
globalCsslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles.WeDevMsgBox.css"));
globalCsslink.Attributes.Add("type", "text/css");
globalCsslink.Attributes.Add("rel", "stylesheet");
globalCsslink.EnableViewState = false;
target.Controls.Add(globalCsslink);
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.ID = "MsgBxStyle";
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles." + Style.ToString().ToLower() + ".css"));
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
csslink.EnableViewState = false;
target.Controls.Add(csslink);
}
}
Update:
PS: I'm tring to use control in generic handler (ashx) where I call ShowMsgBox method which is a method in a class and not in a page or user control.
ShowMsgBox method should create an instance of MsgBox control and render it then return the html code to ashx class :
var htmlCode = MyClass.ShowMsgBox("myMsg");
context.Response.write(htmlCode);
I built a custom ASP.NET control ...
I'm tring to use control in generic handler (ashx) ... not in a page or user control.
A Page is a handler. You want to use a convenience provided by the Page class, but you don't want to inherit from Page. The niceties of Page, such as ClientScript, expect a Page from which to get various information.
You can provide a dummy Page object to your control by setting the Page property of your custom Control:
this.Page = new Page();
...then you will need to set various properties (assuming they are public) which are expected by ClientScriptManager.GetWebResourceUrl():
this.Page.Foo = "bar";
then you can call:
this.Page.ClientScript.GetWebResourceUrl(...);
If this is the specific class that inherits from WebControl page shouldn't be null. If its another class that you are rendering as part of a hierarchy you can add a parameter of type Page and pass the reference of the current page to it.

How to get the page calling the usercontrol

I have a user control .Is there some way to get the page in which usercontrol is available ?
In your usercontrol write this method
protected void MyMethod()
{
Page myParent = this.Page;
...
}
You want the Page property.
If you need to write back to a page of a certain type, you'll have to cast:
var myUserPage = Page as MyCustomUserPageClass;
if (myUserPage != null) {
myUserPage.Foo = "bar";
}

Dynamically adding Content blocks to Masterpage fails after Master.FindControl

I've encountered an odd problem that doesn't make any sense to me. I am trying to dynamically set up MasterPage Content controls on a page. I have it working nicely with the following code:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = "~/MasterPages/Default.master";
string existantContentPlaceHolderID = "ContentPlaceHolder1";
string nonExistantContentPlaceHolderID = "foo";
//Control c = Master.FindControl(existantContentPlaceHolderID);
//Control c1 = Master.FindControl(nonExistantContentPlaceHolderID);
TextBox t = new TextBox
{
Text = "Text"
};
ITemplate iTemplate = new GenericITemplate(container => container.Controls.Add(t));
AddContentTemplate(existantContentPlaceHolderID, iTemplate);
}
public delegate void InstantiateTemplateDelegate(Control container);
public class GenericITemplate : ITemplate
{
private readonly InstantiateTemplateDelegate m_instantiateTemplate;
public void InstantiateIn(Control container)
{
m_instantiateTemplate(container);
}
public GenericITemplate(InstantiateTemplateDelegate instantiateTemplate)
{
m_instantiateTemplate = instantiateTemplate;
}
}
This works great, except I want to be able to double-check that the contentPlaceHolderIDs exist on the MasterPage before calling AddContentTemplate as the Page will throw an error if you add a Content control that points to a non-existing ContentPlaceHolder.
The problem I am having is that in the above example when I call one of the commented Master.FindControl lines, the TextBox no longer renders.
Does anyone have any ideas why this might be... I cannot makes heads or tails of what is going on.
Thanks,
Max
The problem is that AddContentTemplate just records its parameters in a hashtable ready to be combined with the master page instance when it is created. Calling it after the master page has been created won't do anything, and reading the Master property causes the master page to be created.
The best way I can see around this is to create a separate instance of the master page with LoadControl, which you can inspect without affecting the page's own Master property...
MasterPage testMaster = (MasterPage) LoadControl( MasterPageFile );
Control c = testMaster.FindControl(existantContentPlaceHolderID);
There's some overhead in creating a second instance, but it's not immediately obvious to me whether it will be worth worrying about.

Categories

Resources