2009-12-06 Last night, I created a new special event "theme" for the Welcome form. The holiday scene included the typical background image down the left side and a predictable modification to the site logo. But it also included some javascript fun that I planted on the master page. It didn't take long before I became unsatisfied with the idea of modifying the master manually to support a special event theme that changes automagically. So I graduated to creating a separate theme containing the extra script. That would relieve me of having to remove the script from the main master page (in favor of swapping master pages), but it still didn't get it. What I needed was a mod to the specialevents XML to include the path to a special event master page, and proper event handling on the Welcome form EARLY ENOUGH to programmatically assign a new value to the Page.MasterPageFile property. 1. SCHEMA First things first. I needed to change the special events XML schema to include a path to a master page, if one was to be used. The addition of a node achieved this. Christmas Note the data in the node is a virtual path and file name. By the way, the original how-to on this feature is http://www.halfgk.com/howto_imageRotation.txt 2. CODE The special events dataset, dsSpecialEvents, is declared Public-ly at the top of the class. Ordinarily, the Page_Load() event handler would fill the dataset via a function designed to get all of the data the web form requires (LoadSpecialEvents() is called from within Page_GetData()); then the subs to assemble the style and so forth would be called immediately afterward. All of that works very well for everything associated with the special events EXCEPT the new master page. Masters must be implemented very early on in the lifecycle - so early, in fact, it requires the addition of a PreInit event handler. As such, the only change I really need to the existing code -- as opposed to adding new code -- is to move the call to LoadSpecialEvents() into the new Page_PreInit() event handler. Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit '2009-12-06 'created to handle specification of a special events master page Dim strSpecialEventMasterPage As String = String.Empty 'load dataset from xml_specialevents.xml -- these are display instructions (replacement image, logo, etc.) dsSpecialEvents = LoadSpecialEvents() The rest is new code. I needed three routines: one to get the proper master page path (if one exists), one to verify the path, and one to assign it to the MasterPageFile property. strSpecialEventMasterPage = GetSpecialEventMasterPage() If MasterPageIsValid(strSpecialEventMasterPage) Then Call SetMasterPage(strSpecialEventMasterPage) End If End Sub GetSpecialEventMasterPage() does exactly the same thing AssembleSpecialEventStyle() does -- except it only grabs the data from the new node* and spits it back to the string strSpecialEventMasterPage (above). * I'm fairly satisfied with how this is implemented, although there is one change I would make: Instead of having code parse the specialevents xml file TWICE - once in Page_PreInit() and again during Page_Load() -- I should simply grab all the values I need during the PreInit() event and store them for use later. Now that I've got the string, I want to make certain it actually points to a file in that path. Originally, The MasterPageIsValid() function was very small: Private Function MasterPageIsValid(ByVal strMasterPagePath As String) As Boolean '2009-12-06 'ensure the special event master page actually exists before trying to assign it. 'called from the PreInit event handler Return File.Exists(Server.MapPath(strMasterPagePath)) End Function There's only one line of actual code - it returns a Boolean. Simple. The problem with this, though, is that the page it looks for doesn't have to be a master - it just had to be an actual file and path. Master pages are a specific type of Web User Control; pointing to "howto.aspx" will surely cause an exception. We can fix this potential problem in a low-tech way. Private Function MasterPageIsValid(ByVal strMasterPagePath As String) As Boolean '2009-12-06 'ensure the special event master page actually exists before trying to assign it. 'called from the PreInit event handler If Right(strMasterPagePath.TrimEnd, 7) = ".master" Then Return File.Exists(Server.MapPath(strMasterPagePath)) Else Return False End If End Function Now the value passed in for strMasterPagePath has to end in ".master" in order to be evaluated. Otherwise, the function simply returns false. The SetMasterPage() sub is called only if MasterPageIsValid() returns TRUE. Protected Sub SetMasterPage(ByVal strMasterPagePath As String) '2009-12-06 'called from PreInit event handler AFTER ValidateSpecialEventMastPage() is called Me.Page.MasterPageFile = strMasterPagePath End Sub 3. MISC NOTES It's important to point out that the Welcome form -- upon which all of this is happening -- still declares the regular master page in the Page directive. <%@ Page Language="VB" MasterPageFile="~/Theme2.master" ... This can be considered the default master. The way I've set up this new master page assignment subsystem provides multiple opportunities for the default master to be retained: - The node in the specialevents XML doc is blank for all events not using a separate master page. MasterPageIsValid() will return FALSE for an empty value. - MasterPageIsValid() ensures a selected, non-blank value must resolve to an actual file. Otherwise, the function returns FALSE. - MasterPageIsValid() ensures a selected, non-blank value must resolve to an actual .master file. Otherwise, the function returns FALSE. - SetMasterPage will implement a new value for the master page file only if MasterPageIsValid() has returned TRUE for that value. For more information, check out the following article. It gave me what I needed to get this off the ground. http://www.asp.net/%28S%28sf10gzjodvrpce55el2p5cnk%29%29/learn/master-pages/tutorial-09-vb.aspx That should be it for now! Contact me using the site's contact form if you have questions. Feel free to use the code in your projects. A shout out in your project would be thoughtful. Also, drop me a line and let me know how you might have tweaked things to better suit your needs. Finally, I wouldn't profess to be THE expert on matters represented in my code -- so drop me a line if you have constructive suggestions, too. I'd like to hear from you! Best, halfgk copyright 2009 halfgk.com