Important Notice from AspDotNetStorefront
It is with dismay that we report that we have been forced, through the action of hackers, to shut off write-access to this forum. We are keen to leave the wealth of material available to you for research. We have opened a new forum from which our community of users can seek help, support and advice from us and from each other. To post a new question to our community, please visit: http://forums.vortx.com
Results 1 to 4 of 4

Thread: Template (Master Page) Defined Menu's

  1. #1
    cjbarth is offline Senior Member
    Join Date
    Oct 2008
    Posts
    392

    Default Template (Master Page) Defined Menu's

    It seems that page.menu.xml.config is hard-coded in to various source files. I would expect that it would at least be an AppConfig.

    This leads to a rather significant problem: how to I specify which xml.config file I want the menu to use from my template.master file?

    My site necessitates that once a user log on they get a different menu and as users move through the site some menu items changes to make them more relevant to the content they are looking at.

    I was considering using nested master pages in order to accomplish this, but I can't seem to find a way to embed a menu definition in to the master page. Is there a setting I'm missing or can someone help me with the modifications that need to be made to the code to support this?
    Last edited by cjbarth; 05-07-2010 at 04:43 PM.

  2. #2
    cjbarth is offline Senior Member
    Join Date
    Oct 2008
    Posts
    392

    Default

    The easiest workaround I found for this is to put some If...Then statements in the master page. Some menu's would have static items, and only one could be the dynamically built menu.

    It would be ideal if we could set a property (perhaps the first menu item) to be the name of the XML file and then the code would read that menu item and display the correct item. That way we could programatically set the XML file we wanted for the menu directly from any page.

    Code:
    <div class="LeftNavi InfoColumnBackground">
        <%
            If ThisCustomer.CustomerID <> 0 Then
        %>
        <asp:Menu ID="aspnetMenu" runat="server" MaximumDynamicDisplayLevels="4" StaticDisplayLevels="2">
            <DynamicItemTemplate>
                <%# Eval("Text") %>
            </DynamicItemTemplate>
        </asp:Menu>
        <%# Eval("Text") %>
        <%
        Else
        %>
        <asp:Menu ID="Menu1" runat="server" MaximumDynamicDisplayLevels="4" StaticDisplayLevels="2">
            <DynamicItemTemplate>
                <%# Eval("Text") %>
            </DynamicItemTemplate>
            <Items>
                <asp:MenuItem Text="New Item" Value="New Item"></asp:MenuItem>
            </Items>
        </asp:Menu>
        <%
        End If
        %>
    </div>

  3. #3
    cjbarth is offline Senior Member
    Join Date
    Oct 2008
    Posts
    392

    Default

    I was working with this customization problem a little more and found that the template can be customized using Topic pages (sort of).

    Master Mod

    In my master page I defined several sections that needed to be changed for certain pages. So my master page now has several <asp:ContentPlaceHolder /> tags, each with a different ID. Inside of those tags I put the default content for that section.

    web.config Mod

    In the web.config there is a section for routes. I added the following line:

    Code:
    <add name="TopicNoContainer" url="t3-{Topic}.aspx" virtualPath="~/driver3.aspx" checkPhysicalUrlAccess="false" />
    I then copied driver.aspx to driver3.aspx (don't copy the driver.aspx.vb) and modified it to include the content that I wanted to replace in the master page.

    For example:

    Code:
    <%@ Page Language="vb" Inherits="AspDotNetStorefront.driver" CodeFile="driver.aspx.vb"
        EnableEventValidation="false" MasterPageFile="~/App_Templates/Skin_1/template.master" %>
    
    <%@ Register TagPrefix="aspdnsf" TagName="Topic" Src="~/Controls/TopicControl.ascx" %>
    <asp:Content ID="Content1" runat="server" ContentPlaceHolderID="PageContent">
        <asp:Panel ID="pnlContent" runat="server">
            <aspdnsf:Topic ID="Topic1" runat="server" EnforceDisclaimer="true" EnforcePassword="true"
                EnforceSubscription="true" AllowSEPropogation="true" />
        </asp:Panel>
    </asp:Content>
    became:

    Code:
    <asp:Content ID="Content2" ContentPlaceHolderID="CustomMenuItems" runat="Server">
        <asp:Menu ID="Menu2" runat="server" MaximumDynamicDisplayLevels="4" StaticSubMenuIndent="10px"
            StaticEnableDefaultPopOutImage="False">
            <DynamicHoverStyle CssClass="aspnetMenu_DynamicHoverStyle" />
            <DynamicMenuItemStyle CssClass="aspnetMenu_DynamicMenuItemStyle" />
            <DynamicMenuStyle CssClass="aspnetMenu_DynamicMenuStyle" />
            <DynamicSelectedStyle CssClass="aspnetMenu_DynamicSelectedStyle" />
            <StaticHoverStyle CssClass="aspnetMenu_StaticHoverStyle" />
            <StaticMenuStyle CssClass="aspnetMenu_StaticMenuStyle" />
            <StaticSelectedStyle CssClass="aspnetMenu_StaticSelectedStyle" />
            <StaticMenuItemStyle CssClass="aspnetMenu_StaticMenuItemStyle" />
            <Items>
                <asp:MenuItem Text="Test Item" NavigateUrl="~/default.aspx"></asp:MenuItem>
            </Items>
        </asp:Menu>
    </asp:Content>
    <asp:Content ID="Content3" ContentPlaceHolderID="HelpBox" runat="Server">
        <div class="OrangeTitles">
            FAQ</div>
        <br />
        <div class="InfoText">
            <asp:Literal ID="Literal1" runat="server" Text='<%$ Tokens:Topic, faq %>' />
            <br />
            <br />
        </div>
    </asp:Content>
    The Topic Page

    The topic page can be defined as usual in the admin console and can be accessed via t3-[topic].aspx.

    Auto Redirect

    If you want that particular topic page to automatically redirect to the version with the new template you can modify the driver.aspx.vb file. Modify the CheckForRedirect Sub to look like the following:

    Code:
    Private Sub CheckForRedirect(ByVal topic As String)
    	If RedirectPages.ContainsKey(topic) Then
    		Server.Transfer(RedirectPages(topic))
    	End If
    	If CommonLogic.ServerVariables("HTTP_HOST").IndexOf("t3", StringComparison.InvariantCultureIgnoreCase) <> -1 Then
    		Dim _redirDict As New List(Of String)
    		_redirDict.Add("menutest")
    
    		If _redirDict.Contains(topic) Then
    			Response.Redirect("~/t3-" & topic & ".aspx")
    		End If
    	End If
    End Sub
    You'll notice that the second If statement was added to automatically detect and redirect the page if necessary. This page will need to be modified for every topic you want redirected, but it doesn't need to be compiled or anything, so it is a quick and easy change.

    Completely Different Master Page

    If you wanted a completely different Master Page for this new topic page then you could include the following function in the CodeBehind file:

    Code:
    Protected Overrides Function OverrideTemplate() As String
    	If HttpContext.Current.Items("RequestedPage").ToLowerInvariant.StartsWith("t3") Then
    		Return "master.template"
    	End If
    
    	Return ""
    End Function
    Then whenever the topic page is called and it starts with "t3-" it will get the alternate master page. With these two blocks of code a call for a certain topic page made to t-mytopic.aspx will automatically be redirected to t3-mytopic.aspx and then be given a new master page. On this new master page there can be as many <asp:ContentPlaceHolder /> tags as you want because driver3.aspx will be providing the content to them.
    Last edited by cjbarth; 05-11-2010 at 03:51 PM.

  4. #4
    cjbarth is offline Senior Member
    Join Date
    Oct 2008
    Posts
    392

    Default

    My master page customization continues...

    I think I finally have something that will work for every page. Basically what I was looking for was the ability to customize various parts of my site based on which department's pages you were looking at. I didn't want to get a whole new master page for each department and I didn't want to have completely different ASPDNSF store instances.

    What I've finally decided on is a hybrid of some of the things mentioned earlier on in this post.

    web.config Mod

    The first thing that I did was modify my web.config file.

    I added this line to the <routeTable><routes> section:

    Code:
    <add name="SiteSection" url="{sitesection}/{pagename}" virtualPath="~/sitesection.aspx" checkPhysicalUrlAccess="false" />
    This will take any link that looks like http://server/sitesection/page.aspx, and make a call to the sitesection.aspx page.

    sitesection.aspx

    The sitesection.aspx page is quite simple:

    Code:
    <%@ Page Title="" Language="VB" MasterPageFile="~/App_Templates/Skin_1/template.master" AutoEventWireup="false" CodeFile="sitesection.aspx.vb" Inherits="AspDotNetStorefront.SiteSection" %>
    The CodeBehind page is also very simple:

    Code:
    Imports AspDotNetStorefrontCore
    
    Namespace AspDotNetStorefront
    
        Partial Public Class SiteSection
            Inherits SkinBase
    
            Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                Response.Cookies("SiteSection").Value = CommonLogic.QueryStringCanBeDangerousContent("sitesection")
                Response.Redirect("~/" & CommonLogic.QueryStringCanBeDangerousContent("pagename"))
            End Sub
        End Class
    End Namespace
    This code simply sets a session cookie with whatever the text of the sitesection of http://server/sitesection/page.aspx is. It then redirects to http://server/page.aspx which will allow the normal routing rules to do their work.

    Modifying Master.Template

    Now that we have a session cookie that we can refer to we can modify the master.template file to act based on the contents of that cookie.

    There are two ways that we can act based on the cookie. The first is to have some in-line code blocks. The following example will show how to insert a code block that will act based on the value of the cookie.

    Code:
    <%
    If Request.Cookies("sitesection") IsNot Nothing AndAlso Request.Cookies("sitesection").Value.ToLowerInvariant = "altsite" Then
    %>
    [some HTML to appear on the page]
    <%
    End If
    %>
    A second way to include content on the master.template based on the value of the cookies is:

    Code:
    <%
    Response.Write(CookieContentFunction())
    %>
    The above requires a modification to the CodeBehind file.

    Modifying Master.Template CodeBehind

    The modification to the CodeBehind file can be as complex as you want it to be; the only thing is that it should return a String that represents valid HTML.

    With the above example the CookieContentFunction might look like this (added to the App_Code/MasterPageBase.vb file):

    Code:
    Private Function CookieContentFunction() As String
    	If Request.Cookies("sitesection") IsNot Nothing Then
    		If Request.Cookies("sitesection").Value.ToLowerInvariant = "altsite" Then
    			Return "<b>Your looking at the AltSite Mod.</b>"
    		End If
    	End IF
    
    	Return Nothing
    End Function
    Something even cooler would be modifying the menu after it is already built.

    Modify Menu

    In the App_Code/MasterPageBase.vb file a line can be added to the OnPreRender Sub directly after the call to SetupMenu. I named the new Sub SetupCustomMenu.

    Code:
    Private Sub SetupCustomMenu()
    	If aspnetMenu IsNot Nothing Then
    		If Request.Cookies("sitesection") IsNot Nothing Then
    			If Request.Cookies("sitesection").Value.ToLowerInvariant = "altsite" Then
    				Dim test As New MenuItem("Test Item", Nothing, Nothing, "~/default.aspx")
    				aspnetMenu.Items(0).ChildItems.Add(test)
    			End If
    		End If
    	End If
    End Sub
    This will add an item to the root of the menu that was automatically built by the page.menu.xml.config file. This method can be used to add, or delete, as many menu items as desired based on the value of that cookie. Thus, the menu can be changed with minimal effort by simply calling a link. This cookie can also be set any other way via code.

    This allows menus, logos, and other elements on the page to be easily changed without having to maintain multiple master pages.
    Last edited by cjbarth; 05-13-2010 at 03:09 PM.