CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Eric Wise

Business & .NET

Calling a Master Page User Control from a Page User Control

Now if that title isn't a mouthful, I don't know what is.  Anyways, this is something mostly for my benefit because I conveniently forget about this little trick and then have to go rooting through my code to remember and I'd rather have Google index it for me.  =)

So I have this nifty little status message user control in the master page of my current project. It basically leverages a repeater to show a list of status messages with icons next to them based upon the type/severity. The idea is to have a method in the master page that takes a message and type as an argument and adds the message to an internal list which binds before render when all the processing is complete.

The problem is, I want to call to the user control from a user control in a page, so I have to jump two levels "up the chain" so to speak. Now, I hate FindControl() so I want it to be strongly typed to, so here is the solution I came up with.

Create a base page for the master page

Create a class, inherit it from master page, expose a virtual method which in my case writes a message. In this base page, I'm just dumping the message out in response.write since there's no user control here necessarily to handle it.  MessageType is just an Enum I created with types like Success, Warning, Error, etc.

public class BaseMasterPage : MasterPage
{
    public virtual void WriteMessage(string Message, MessageType Type)
    {
        Response.Write(Message);
    }
}

Inherit your master page with the control from the BaseMasterPage and override the virtual method

The beauty of this is that I now have a common interface across my master pages for accepting messages from pages and user controls. They can all handle the messages in their own way.  In the case of the following master page, I get a strongly typed call to my status message control (as I said before, it binds in the PreRender since it will have collected all the messages by then):

public partial class MyMasterPage : BaseMasterPage
{

    protected void Page_PreRender(object sender, EventArgs e)
    {
        StatusViewer1.BindStatuses();
    }
   
    public override void WriteMessage(string Message, MessageType Type)
    {
        StatusViewer1.AddStatusItem(new StatusItem(Type, Message));
    }

}

Internally, the viewer just as a List<StatusItem> of which status item is just a barebones object for the strongly typed generic (I love those damn generics).

In the case of a user control on a page, you just have to ensure that the master page being called is of type BaseMasterPage, and then pass the message out accordingly. Here's a snippet from one of my user controls:

if (Page.Master is BaseMasterPage)
{
     ((BaseMasterPage)Page.Master).WriteMessage("Some warning message.", MessageType.WARNING);
}
else
     throw new Exception("You're supposed to inherit from BaseMasterPage, Doofus.");

Anyways, the point is that inheriting from your own custom base classes lends you a lot of extra firepower when it comes to dealing with pages and master pages and .net 2.0.  Creating a BaseMasterPage and BasePage are two of the first things I do in about any project.

 



Comments

Derick Bailey said:

I had a similar situation where i wanted to display a simple string message in the master page. i thought about doing basically what you just described, originally, but ended up with a different method:

i abstracted my solution out a little more and created an external assembly that has a "publish" method and raises a known event when something is published.  i then had the master page subscribe to that event, and display the text.

when comparing the two, i'm not sure which is the "right" way to do it. I've re-used the same publisher over and over again in different projects, so I think i did the right thing based on component reuse. however, it does add some overhead via event delegates, etc. I guess the largest reason i went the way i did was because i don't like the idea of doing the "if (Page.MasterPage is BaseMasterPage) " logic. In my mind, i should try to write code that prevents this type of type checking logic (it feels like a leaky abstraction, to me).

what are your thoughts on the basic concept that i implemented, and my thoughts on not liking that if statement?

thanks.

# January 8, 2007 4:44 PM

Eric Wise said:

Your concept is defintely better from a reuse perspective and I wouldn't be too concerned for delegate performance.

The if statements dont bother me so much because they are in user controls only since pages can strongly type their master page declaritively. I could address this by implementing a base user control and getting a pointer to the BaseMasterPage one time early on and reuse that pointer throughout the process.

# January 8, 2007 6:38 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors