Kristian Oye
Kristian Oye

Reputation: 1202

How to Pass Custom WebViewPage Property from View to Layout?

I have defined a custom WebViewPage type with custom properties used by our site:

  public abstract class BasePage : WebViewPage
  {
        public string OmniPageName { get; set; }
  }

  public abstract class BasePage<TModel> : WebViewPage<TModel> where TModel: class
  {
        public string OmniPageName { get; set; }
  }

And in my view I set this property like:

Index.cshtml:

@{
    OmniPageName = "Home";
}

This is set fine and usable within the view, but I also need to access this value in the layout. I am hoping I can access the view instance from within the layout's InitializePage() override but I cannot figure out how. Something like:

protected override void InitializePage()
{
   //  this.OmniPageName = (expr:child view).OmniPageName
   base.InitializePage();
}

And then use:

Layout.cshtml:

<!-- render value from Index.cshtml -->
<div class="pagelet" data-omnipage="@OmniPageName"></div> 

Currently, the Layout's value for this property is null. I could use the ViewBag but there are other properties that are not simple, scalar values and I want to leverage the IDE's enforcement of strong typing to prevent mistakes.

Any help would be greatly appreciated!

Upvotes: 1

Views: 2113

Answers (1)

Nico
Nico

Reputation: 12683

There is no reason why you cant do it exactly as you have written.

However you need to make sure that the web.Config is set to all views to inherit from your custom view page. (Not sure if this is already done).

In the web.config found ~/Views/web.config folderSet the pageBaseType to the type of your view. Such as

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="YourNameSpace.BasePage"> <!-- Edit This line -->
        <namespaces>
          <add namespace="System.Web.Mvc" />
          <add namespace="System.Web.Mvc.Ajax" />
          <add namespace="System.Web.Mvc.Html" />
          <add namespace="System.Web.Routing" />
          <!-- ommited -->
        </namespaces>
    </pages>
</system.web.webPages.razor>

Now from what we can see you only have a custom WebViewPage for a Typed model by inheriting from WebViewPage<TModel>. However layout pages typically not typed. Therefore you should create another class that inherits from your BaseViewPage such as

public class BaseViewPage : BaseViewPage<dynamic>
{
     //functionality is inherited from BaseViewPage<T>
}

This will inherit all the functionality of your Typed BaseViewPage and allow for non-typed views.

Edit: Now if you test this you still wont get data passed to the Layout page as you will find (set a constructor break point) and a new instance of the BaseViewPage is created for each View rendered. Therefore you need to find a way to pass data in a shared object between the instances. Luckily there are many different shared objects available.

public string OmniPageName
{
    get
    {
        return (ViewBag._OmniPageName ?? "").ToString();
    }
    set
    {
        ViewBag._OmniPageName = value;
    }
}

This is a simple example that uses the ViewBag (<dynamic>) to shared the name. We could use:

  1. ViewData: Essentially the same as ViewBag but is a Dictionary
  2. TempData: This is similar to the ViewData but can persist between requests.

Upvotes: 3

Related Questions