I'm working on a .net 3.5 site, standard website project.
I've written a custom page class in the sites App_Code folder (MyPage).
I also have a master page with a property.
public partial class MyMaster : System.Web.UI.MasterPage
{
...
private string pageID = "";
public string PageID
{
get { return pageID; }
set { pageID = value; }
}
}
I'm trying to reference this property from a property in MyPage.
public class MyPage : System.Web.UI.Page
{
...
public string PageID
{
set
{
((MyMaster)Master).PageID = value;
}
get
{
return ((MyMaster)Master).PageID;
}
}
}
I end up with "The type or namespace name 'MyMaster' could not be found. I've got it working by using FindControl() instead of a property on the MyMaster page, but IDs in the master page could change.
I've tended to do the following with Web Site projects:
In App_Code create the the following:
BaseMaster.cs
using System.Web.UI;
public class BaseMaster : MasterPage
{
public string MyString { get; set; }
}
BasePage.cs:
using System;
using System.Web.UI;
public class BasePage : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (null != Master && Master is BaseMaster)
{
((BaseMaster)Master).MyString = "Some value";
}
}
}
My Master pages then inherit from BaseMaster:
using System;
public partial class Masters_MyMasterPage : BaseMaster
{
protected void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(MyString))
{
// Do something.
}
}
}
And my pages inherit from BasePage:
public partial class _Default : BasePage
I found some background to this, it happens because of the way things are built and referenced.
Everything in App_Code compiles into an assembly.
The rest, aspx files, code behind, masterpages etc, compile into another assemlby that references the App_Code one.
Hence the one way street.
And also why Ben's solution works. Thanks Ben.
Tis all clear to me now.
I realise there are already accepted solutions for this, but I just stumbled across this thread.
The simplest solution is the one listed in the Microsoft website
(http://msdn.microsoft.com/en-us/library/c8y19k6h.ASPX )
Basically it says, your code will work as-is, if you include an extra directive in the child page aspx:
<%# MasterType VirtualPath="~/MyMaster.Master" %>
Then you can directly reference the property in the base MyPage by:
public string PageID
{
set
{
Master.PageID = value;
}
get
{
return Master.PageID;
}
}
Related
I hope you can help me with this. I am creating an internal webforms asp.net site to display a list of internally used documents in different categories.
I decided to create a custom document class to put in a list to hold the documents, and then a custom web user control to display the documents wherever they want them on the site.
The documents class is in a general class file in my App_Code folder.
cabinet.cs
public class Document
{
private string _Url;
private string _Title;
public Document(string URL, string Title)
{
_Url = URL;
_Title = Title;
}
public string URL
{
get { return _Url; }
set { _Url = value; }
}
public string Title
{
get { return _Title; }
set { _Title = value; }
}
}
This code works just fine. Then in my user control I create a list of type document and initiate it in Page_Load(). Then I created a public method to add new documents to the list.
DocDisplay.ascx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class DocDisplay : System.Web.UI.UserControl
{
private List<Document> _DocList;
protected void Page_Load(object sender, EventArgs e)
{
_DocList = new List<Document>();
}
public void Add(string URL, string Title)
{
_DocList.Add(new Document(URL, Title));
}
public void WriteDocuments()
{
foreach (Document doc in _DocList)
{
Response.Write($"<span class='document'><a href='{doc.URL}'>{doc.Title}</a></span>");
}
}
}
I am getting the error in the add method. It says that my object is not to an instance of an object. But I do that in Page_Load.
index.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
pageDocs.Add("index.aspx", "Hello World!");
pageDocs.Add("index.aspx", "Red Rum");
pageDocs.Add("index.aspx", "Lorum Ipsum");
}
I have registered my user control in my index page.
<%# Register Src="~/DocDisplay.ascx" TagPrefix="uc" TagName="DocDisplay" %>
<uc:DocDisplay ID="pageDocs" runat="server" />
So I am not exactly sure why I am getting that error. As far as I can tell, there is nothing wrong with my code. If you could help I would greatly appreciate it.
Events get fired starting from the root of control hierarchy and end at the leaf nodes. Index.Page_Load is being called before DocDisplay.Page_Load has an opportunity to instantiate the list.
The _DocList field needs a value before it can be used by anything, so initialization needs to happen as early as possible. This is accomplished very easily with a field initializer. Declare and assign it all at once:
private List<Document> _DocList = new List<Document>();
When the Index class instantiates its child controls early in the page life cycle, _DocList will immediately have an object reference.
It's tempting to say, "Page_Init will be called sooner; I'll do it there." This may work at first, but if you do any dynamic control loading, you'll soon find out that it's a balancing act. A dynamically loaded control has to play event catch-up, so its Init event can be fired after statically loaded controls have started firing Load events. It's important to use each event for its purpose, and not for its timing, and use constructors (and field initializers) to initialize non-control class state.
I'm trying to write variables from my code behind but am being told "The name 'X' does not exist in the current context."
When I search for this error, I see that they should be declared public or protected at the class level, and I have done that.
I try writing the variable in default.aspx using:
<%=metaRedirect%>
or
<%#metaRedirect%>
My default.aspx.cs is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace go
{
public partial class _default : System.Web.UI.Page
{
protected string message1 = "";
protected string url = "";
protected string shortCode = "";
protected string jsRedirect = "";
protected string metaRedirect = "";
protected void Page_Load(object sender, EventArgs e) {
//do stuff
}
}
Edit: I have also tried declaring them like this:
public partial class _default : System.Web.UI.Page
{
protected string message1 { get; set; }
protected string url { get; set; }
protected string shortCode { get; set; }
protected string jsRedirect { get; set; }
protected string metaRedirect { get; set; }
With no difference.
Edit 2: Is it possible I am missing something from the first line of the .aspx file? I have:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" %>
Sounds like your page isn't properly hooked up to the class. Make sure you've got Inherits="go._default" in your page header in your aspx page.
EDIT After your edit, this is definitely your problem.
Also, you can definitely use fields if you want instead of properties (but I always recommend properties), and you can use protected instead of public. Things shouldn't be public unless you really do want to access them from outside of this class or inheritance chain.
As you are using binding expression you need to call Page.DataBind()
in the page_load and make the variable Public
public string metaRedirect { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
metaRedirect="Hello World.";
Page.DataBind();
}
And try:
<%#metaRedirect%>
or you can just Simply call it like
<%= metaRedirect%>
I have an application that uses 2 master pages. One for main pages and one for Popup pages. These both inherit from Masterpages
public partial class MainMasterPage : System.Web.UI.MasterPage
{
UserBO objUser = null;
public UserBO GetCurrentUser()
{
UserBO userBO = new UserBO();
.....
.....
return userBO;
}
}
public partial class PopupMasterPage : System.Web.UI.MasterPage
{
UserBO objUser = null;
public UserBO GetCurrentUser()
{
UserBO userBO = new UserBO();
.....
.....
return userBO;
}
}
So far so good. So my content pages all Inherit from a base class. The base class has a method that
calls the GetCurrentUser from the Base class.
public class BasePage : Page
{
//.....
protected UserBO GetCurrentUserFromMasterPage()
{
this.Master
Elsa.MasterPages.MainMasterPage master = (Elsa.MasterPages.MainMasterPage )this.Master;
return master.GetCurrentUser();
}
}
So here you can see that the base page casts the MasterPage and then calls GetCurrentUser.
Just for background... The masterpages get current user logged into the system and then draws itself using the info. If the user is in the session it gets it otherwise it loads from the database. I dont want the content pages to do the same so I wanted the base page to always get the current user for the content page from the master.
However my problem is, that because there is 2 master pages and all web pages are derived from Base
page.. I need to be able to cast to the correct master.
public partial class MyMainPage : Elsa.Pages.BasePage
{
private long _userId = -1;
public partial class MyPopupPage : Elsa.Pages.BasePage
{
private long _userId = -1;
If I put in the MasterType directive I can call the method in the content page for the correct Master.
But I dont want to call it from the content as its common method so I need it in the base.
So does anyone know how to handle this. I was thinking on deriving the BasePage again for a PopupBasePage and over writing the GetCurrentUserFromMasterPage() to cast to the popup master.
Or do I pass something into the BasePage constructor to tell it what to cast to.
I want to keep the impact to all my web pages to a minium as I have a lot of web pages.
Thanks M
You can insert an extra MasterPage as the base class for your 2 current ones:
public partial class SiteMasterPage : System.Web.UI.MasterPage
{
....
// GetCurrentUser
}
public partial class MainMasterPage : SiteMasterPage
{
....
}
public partial class PopupMasterPage : SiteMasterPage
{
}
This will allow you to implement other common features and markup (include of CSS files) in one place as well.
Does it make sense for you
using Reflection:
Master.GetType().GetMethod("GetCurrentUser").Invoke();
Do this :-
public class MasterPageBase : MasterPage
{
public PageBase PageBase { get { return (PageBase)this.Page; } }
}
public class PageBase : Page
{
// Do your Extensions Here..
}
All Pages there after Inherit from PageBase.
I am to access a method on my master page. I have an error label which I want to update based on error messages I get from my site.
public string ErrorText
{
get { return this.infoLabel.Text; }
set { this.infoLabel.Text = value; }
}
How can I access this from my user control or classes that I set up?
To access the masterpage:
this.Page.Master
then you might need to cast to the actual type of the master page so that you could get the ErrorText property or make your master page implement an interface containing this property.
Page should contain next markup:
<%# MasterType VirtualPath="~/Site.master" %>
then Page.Master will have not a type of MasterPage but your master page's type, i.e.:
public partial class MySiteMaster : MasterPage
{
public string ErrorText { get; set; }
}
Page code-behind:
this.Master.ErrorText = ...;
Another way:
public interface IMyMasterPage
{
string ErrorText { get; set; }
}
(put it to App_Code or better - into class library)
public partial class MySiteMaster : MasterPage, IMyMasterPage { }
Usage:
((IMyMasterPage )this.Page.Master).ErrorText = ...;
I have quite simple site structure with one mastepage and a bunch of pages. The mastepage is quite advanced though and I need from the page be able to control certain aspects of the Masterpage.
I want to be able to enter these directive in the aspx file to not clutter the code behind files.
My idea was to create different "directive" user controls such as SeoDirective:
using System;
public partial class includes_SeoDirective : System.Web.UI.UserControl
{
public string Title { get; set; }
public string MetaDescription { get; set; }
public string MetaKeywords { get; set; }
}
I include this directive in those pages that need to override the default mastepage settings.
<offerta:SeoDirective runat="server" Title="About Us" MetaDescription="Helloworld"/>
In my masterpage I look if there's any directives:
includes_SeoDirective seo = (includes_SeoDirective) ContentPlaceHolder1.Controls.Children().FirstOrDefault(e => e is includes_SeoDirective);
(Children() is an extension so I can work with Linq on a ControlCollection)
Now to my question: I'm not to happy about this solution might be a bit bloated?
I'm looking for alternative solutions where I can created these tags in the aspx file.
I've looked at the trick where I extend the Page, but that requiries we to modify the VS configs for the project to compile, so I dropped that solutions.
As far as I am aware, there isn't a standard way of doing this. I have done this same thing in the past in much the same way you have, except I used an interface on the pages that I needed the master page to look for, which defined a method it could call to do specific logic with the master page.
You might be able to use this same paradigm:
ISpecialPage.cs:
public interface ISpecialPage
{
string Title { get; set; }
string MetaDescription { get; set; }
string MetaKeywords { get; set; }
}
MyPage.aspx:
public partial class MyPage : System.Web.UI.Page, ISpecialPage
{
public string Title { get; set; }
public string MetaDescription { get; set; }
public string MetaKeywords { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
this.Title = "Some title";
this.MetaDescription = "Some description";
this.MetaKeywords = "Some keywords";
}
}
MasterPage.master:
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (this.Context.Handler is ISpecialPage)
{
ISpecialPage specialPage = (ISpecialPage)this.Context.Handler;
// Logic to read the properties from the ISpecialPage and apply them to the MasterPage here
}
}
}
This way you can handle all MasterPage logic in the master page code behind file, and simply use the interface on pages you need to provide certain information.
Hope this helps you!