ASP.NET: Call function in MasterPage through UserControl
Asked Answered
S

5

6

Calling a function from the MasterPage in a Page is quite straigt forward but how do I call it for a UserControl:

Adding <%@ MasterType VirtualPath="~/MasterPage.master" %>, doesn't work on UserControls.

So this.Page.Master.MyFunction() fails :(

Story answered 18/9, 2009 at 12:20 Comment(0)
H
7

Niels,

Leverage reflection (as suggested by JDunkerley) is one approach to the problem. Another you might consider is implementing an interface:

  1. Create an interface that includes your method.
  2. Implement the interface in your master page
  3. From your control, reference this.Page.Master via the interface type.
  4. Call your method.

This is a better OO approach, leads to less coupling, and will certainly perform better than runtime reflection.

I hope this helps!

Hamper answered 18/9, 2009 at 13:55 Comment(1)
Glad to be of assistance! Happy coding :-)Hamper
G
12

You have to cast the this.Page.Master first as the Master property of the Page is of type System.Web.UI.MasterPage.

e.g.

((MyMaster)this.Page.Master).MyFunction();

You could check the type of the underlying master page by adding a property to the code behind of the user control:

    public string MType
    {
        get { return this.Page.Master.GetType().FullName; }
    }

and print the result out in the User control markup, e.g. add this line to make it print out as a comment in the source code:

<!-- <%= MType %> //-->
Gestalt answered 18/9, 2009 at 12:35 Comment(4)
I get an error saying that it can't find type or namespace _Master??Story
you can try checking the type of the master page at RunTime. Will update the answer in a secondGestalt
The type is ASP.masterpage_master but is not available in compile time.Story
Do you have an Inherits entry on the <%@ Master %> tag in the mark up for the MasterPage? I just tried on my ASP.Net site and the code works fine.Gestalt
H
7

Niels,

Leverage reflection (as suggested by JDunkerley) is one approach to the problem. Another you might consider is implementing an interface:

  1. Create an interface that includes your method.
  2. Implement the interface in your master page
  3. From your control, reference this.Page.Master via the interface type.
  4. Call your method.

This is a better OO approach, leads to less coupling, and will certainly perform better than runtime reflection.

I hope this helps!

Hamper answered 18/9, 2009 at 13:55 Comment(1)
Glad to be of assistance! Happy coding :-)Hamper
M
4

You are couppling your code very thighly if you call a function on the masterpage from within your user control.

The Control can only be used on pages that are based on that master. I think this is usually a bad design, and it will violate at least the law of demeter.

What exactly do you want to accomplish in your control?

Merralee answered 18/9, 2009 at 13:28 Comment(0)
B
1

JDunkerley has it right. But allow me to explain how to decouple it using MVP so you can work toward avoiding the design issue Heiko Hatzfeld is talking about.

Basically, implement the MVP pattern for both your control and your master page. See here for instructions on how to do that. Declare the method you want to call in the master's interface (IMasterView). Next create a class that will control the relationship between the two components; we'll call it the PageController class. Place an instance of this class in request state for each request by adding the following line to global.asax.cs:

/* global.asax.cs */
protected void Application_BeginRequest(object sender, EventArgs e)
{
    // ...
    HttpContext.Current.Items["Controller"] = new PageController();
    // ...
}

You can then access this instance from each of the presenters (master and control) via the following line of code:

var controller = HttpContext.Current.Items["Controller"] as PageController;

You can then implement an event or some other mechanism to allow the control to invoke the method on the master in a decoupled manner through this shared object. For example:

/* PageController.cs */
public event EventHandler SomeEvent;

protected virtual void OnSomeEvent(EventArgs e)
{
    Debug.Assert(null != e);

    var handler = this.SomeEvent;
    if (null != handler)
        handler(this, e);
}

public void FireSomeEvent()
{
   this.OnSomeEvent(EventArgs.Empty);
}

/* ControlPresenter.cs */
public ControlPresenter(IControlView view)
    : base()
{
    view.EventFired += (sender, e) =>
    {
        var controller = HttpContext.Current.Items["Controller"] as PageController;
        controller.FireSomeEvent();
    };
}

/* MasterPresenter.cs */
public MasterPresenter (IMasterView view)
    : base()
{
    var controller = HttpContext.Current.Items["Controller"] as PageController;
    controller.SomeEvent += (sender, e) => view.MyFunction();
}

Make sure the "EventFired" event is declared in your control's interface (IControlView) and implemented in the control. Then all you have to do to affect the master (call its method), is fire this event and the MVP + the PageContoller will take care of the rest.

Cheers

Block answered 18/9, 2009 at 15:42 Comment(0)
A
1

I couldn't get the above answers to work, so here is what worked for me:

You want to reference a master page property from a user control.

Firstly, your master page will have a public property like so :

public string BodyClass
{
    set
    {
        this.masterBody.Attributes.Add("class", value);
    }
}

Now add a reference to the master page in the user control ASCX file like so :

<%@ Register Src="~/Source/MasterPages/Main.master" TagPrefix="MSTR" TagName="MasterPage" %>

Then in the code behind (C# in my case) you have this code :

Main masterPage = (Main)this.Page.Master;
masterPage.BodyClass = "container";

Without the reference to the master page above your user control will not be able to find the master page class.

Afterguard answered 22/2, 2012 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.