简体   繁体   中英

ASP.NET: Call function in MasterPage through UserControl

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 :(

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

eg

((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, eg add this line to make it print out as a comment in the source code:

<!-- <%= MType %> //-->

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!

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM