






















http://www.theserverside.net/articles/showarticle.tss?id=SkinningAnApp
Visitors and followers of the recent Microsoft PDC got a preview of the next generation of ASP.NET, which included many new features including “master pages” and a technique called skinning. While ASP.NET version 2.0 is well over a year away, you can implement these tools yourself today. In this article, we are going to build a sample project that implements a Master Page and skinning.
Skinning is the ability to change the appearance of an application at runtime. Several popular windows applications such as Windows Media Player include skinning support. Skinning your ASP.Net web application can enhance the application appearance and make it more appealing.
So the question is why would you want to implement skinning? There are several reasons you might want to implement skinning, a few of which are mentioned below.
We started playing with skinning in ASP.Net last summer when a client approached us about a web application they wanted to build and share with their sister companies. The application would be hosted on the same server and each sister company wanted to brand the application to match their site. What we settled on doing was creating a single web application with skinning capabilities. We determined what skin to load based on the hostname in the URL. This allows not only the sister companies to just brand the application for their companies but to actually change the look and feel so that it matches their site.
One thing ASP.Net provides is the ability to separate presentation from logic in the form of code behind and presentation files that can inherit from a class. Visual Studio.Net implements this well but it’s implementation only establishes a one to one relationship between the logic class and the presentation (Web Matrix doesn’t provide this feature). With skinning we will extend this to have many presentation files that inherits from single class. This means each skin will perform the same and run the same logic but will have the ability to look different.
In ASP.Net skinning is really easy to implement by taking advantage of ASP.Net’s features for separating code from presentation. You build your application logic in a code behind class that the ASP.Net presentation files inherit from. What we will do in our sample project is create directories for each skin. We will create two skins, one called “Blue’ and another one called “Green”. So the presentation files for “Page.ascx” is “Blue\Pages.ascx” and the other one is “Green\Pages.ascx”. So our application logic will simple choose which presentation file to load and because both presentation files inherit from the same code behind they provide the same functionality. For our sample we will create a drop down box in our Master Page that will change a session state variable that contains the name of the skin.
A Master Page is a single page that provides a consistent layout and style to a series of pages. Take for example a Web Site like below:
This is a very typical layout that includes a header at the top, a menu to the side, and an footer at the bottom. In between all this is the content area which is where the main content of the page goes. You can see an example of this style of page at TheServerSide, Microsoft.com and GotDotNet.com, among others. In this type of page typically the header, footer, and menu stay the same between the different pages. When using Master Pages we build our layout and static content(header, footer, and menu) in the master page and then we define a content area to load the content into. In our model we will be doing this by create an ASPX for our master page and then adding a placeholder control to load the content into. Also in this example we are going to add the ability to skin our master page.
To get the master page working in ASP.Net we need to direct all request to a single page, which we will call “default.aspx”. The “default.aspx” will load the master page skin and then use the requested URL to load the appropriate control in the content area. If you were not skinning you could combine this page in with your master page. This page’s ASPX will be pretty simple and will contain only the HTML tags necessary to form a page.
In order to do redirect all request to “default.aspx” we add a line of code to the Application_BeginRequest event. To handle the redirection we will use the Context.RewritePath method and pass it the location of our single page.
(In GLOBAL.ASAX)
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As _
EventArgs)
'Redirect the call to the default.aspx page
Context.RewritePath(Context.Request.ApplicationPath & _
"/default.aspx")
End Sub
By using the RewritePath method we can transfer the request on the server side without the client ever realizing that another page is handling the request. When this happens a client requests “Page1.aspx” in his browser, it appears that to the user (and their browser) that they are viewing “Page1.aspx” but in reality they are viewing a page generated by “default.aspx”
Now that we have the redirect functionality built lets create our Default.aspx.
<%@ Page Inherits="SkinningSample.PageDirector"%>
<HTML>
<HEAD>
<title>Skinning Sameple</title>
</HEAD>
<body>
<form id="myForm" method="post" runat="server" /> </body>
</HTML>
Notice the only thing in the body is the ASP.Net form tag named myForm. We will get a reference to the form in the code-behind and load the MasterPage skin into it. The code behind for the Default.aspx is as follows.
Public Class PageDirector Inherits System.Web.UI.Page Protected myForm As HtmlForm Private Sub Page_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load 'First we will parse out the filename of the requested page. Dim sFile As String = _ Request.RawUrl.Substring(Request.RawUrl.LastIndexOf("/") + 1) 'We need to rewrite the path back to that of the requested 'page. Without this ASP.Net postback will not work properly Context.RewritePath(sFile) 'The PageSkin must have a placeholder named "ContentArea". 'This placeholder is where we will add the child control for 'the page content Dim myPageSkin As Control = GetSkinFile("MasterPage.ascx") 'Find the ContentArea Placeholder in the PageSkin Dim myContentArea As PlaceHolder = _ CType(myPageSkin.FindControl("contentArea"), PlaceHolder) 'Load the content control and add it to the Controls collection of the 'ContentArea myContentArea.Controls.Add(GetSkinFile("Hello.ascx")) 'Add the PageSkin to the Page's form. myForm.Controls.Add(myPageSkin) End Sub 'This function will retrieve the path to a skin file. Public Function GetSkinFile(ByVal FileName As String) As Control 'For purposes of this example we are storing the 'skin name in the session state. 'Set Varible to skin name Dim sSkin As String = Session("skin") 'If no skin is set Default to Blue. If sSkin = "" Then sSkin = "Blue" 'Pass back a skin path for the file requested. Return LoadControl(String.Format("{0}\skins\{1}\{2}", _ Request.ApplicationPath, sSkin, FileName)) End Function End Class
The first thing we do is parse out the file name from the URL. This is done so that ASP.Net will write out the form to post back to that URL instead of posting back to Default.aspx. Next we declare the variable myPageSkin and load a control called MasterPage.ascx. We use the GetSkinFile method to retrieve the skinned control. The GetSkinMethod simply creates the path of the control based off the session(“skin”) variable and then returns the control from that path. After we have a reference to our “MasterPage.ascx” skin file we set a reference to its ContentArea placeholder. At this point your can put in logic to choose which control to load as content, in this sample we have one content control so we will just load it using the GetSkinFile method. Our final step is to add the MasterPage control to myForm’s control collection.
Now that we have the Default.aspx built and have it set to load the MasterPage.ascx we need to build both the ASCX files and the code behind.
(Code in Blue\MasterPage.ascx)
<%@ Control Inherits="SkinningSample.MasterPage" %>
<FONT face=Arial color=#336699 size=7>Blue Site</FONT>
<P>Change Skin:<asp:DropDownList id=ddlSkin AutoPostBack="True" runat="server"/></P>
<P><asp:PlaceHolder id=ContentArea runat="server" /></P>(Code in Green\MasterPage.ascx)
<%@ Control Inherits="SkinningSample.MasterPage" %>
<FONT face="Courier" color="#39966" size="7">Green Skin</FONT>
<P><asp:PlaceHolder id="ContentArea" runat="server" /></P>
<HR>
<P>Change Skin:
<asp:DropDownList id="ddlSkin" AutoPostBack="True" runat="server"/></P>
As mentioned before we are keeping our samples as simple as possible and as such our master page is pretty light. We simply have a header, the content area, and a drop down list to switch skins. Between the two skins we change the layout slightly and we switch between two different font colors. We’ve talked previously about the ContentArea placeholder and how we will use it to load the content control. In our particular example here we have a drop down list that has a listItem for each skin. This is the drop down we will use to switch skins. Our code behind class for the Master Page looks like this.
Code in MasterPage.vb Public Class MasterPage Inherits System.Web.UI.UserControl Protected WithEvents ddlSkin As DropDownList Private Sub Form_Load(ByVal sender As Object, ByVal e As _ EventArgs) Handles MyBase.Load 'If we have a skin selected and this isn't a postback set the 'selected skin. If Not IsPostBack And Not Session("Skin") = "" Then ddlSkin.Items.Add("Blue") ddlSkin.Items.Add("Green") ddlSkin.SelectedValue = Session("Skin") End If End Sub Private Sub ChangeSkin(ByVal sender As Object, ByVal e As _ EventArgs) Handles ddlSkin.SelectedIndexChanged 'Set the new skin name in the session. Session("Skin") = ddlSkin.SelectedValue 'Reload this page so the skin changes take place. Response.Redirect(Request.RawUrl) End Sub End Class
All we are doing with the MaserPage class is managing the skin drop down list. So we have code to set the selected item and to populate the Session(“skin”) variable with the post back of the drop down list. When we reset the skin we do a redirect back to the current page so that we can reload the skin.
In our sample we have one control called “Hello.ascx”. Building a skinned control works exactly the same way as building the Master Page skin. We will create a ASCX file in each of the skin directories and then a code behind class to add functionality. This control will have three labels, one for the requested URL, one for the current date, and one for the current time.
(Code in Blue\Hello.ascx)
<%@ Control Inherits="SkinningSample.SayHello" %>
<P>
<asp:Label id="lblURL" runat="server" Font-Names="Arial" Font- Italic="True" ForeColor="#00C0C0">The URL you requested was {0}</asp:Label></P>
<P>
<asp:Label id="lblDate" runat="server" Font-Names="Arial" Font- Bold="True" ForeColor="Navy">The Current Date is {0:d}</asp:Label></P>
<P>
<asp:Label id="lblTime" runat="server" Font-Names="Arial" Font- Bold="True" ForeColor="Navy">The Current Time is {0:t}</asp:Label></P>(Code in Green\Hello.ascx)
<%@ Control Inherits="SkinningSample.SayHello" %>
<P>
<asp:Label id="lblDate" runat="server" Font-Names="Courier New"> Date: {0:D}</asp:Label></P>
<P>
<asp:Label id="lblTime" runat="server" Font-Names="Courier New"> Time: {0:T}</asp:Label></P>
<P>
<asp:Label id="lblURL" runat="server" Font-Size="X-Small" Font- Italic="True" Font-Bold="True" ForeColor="Green"> Requested URL: {0}</asp:Label></P>
Once again the files are very simple, each has three labels. The labels have different appearances and positions in the different skins. But both classes in inherit from the SayHello class and thus have the same functionality. Now we just need to build our SayHello class.
Public Class SayHello Inherits System.Web.UI.UserControl Protected lblURL As System.Web.UI.WebControls.Label Protected WithEvents lblDate As System.Web.UI.WebControls.Label Protected WithEvents lblTime As System.Web.UI.WebControls.Label Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load lblURL.Text = String.Format(lblURL.Text, Request.RawUrl) lblDate.Text = String.Format(lblDate.Text, Now.Date.Today) lblTime.Text = String.Format(lblTime.Text, Now.ToLocalTime) End Sub End Class
Again this is a very simple class and all it does is populate the values of the labels. Notice the technique for setting the labels’ text value. When doing skinning it is frequently advantageous to use the string.Format class to set the text of labels, particularly those with dates, times, and currencies. This gives the developer of the skin file more control over how the data is presented. Notice the value of the date label in blue Hello.ascx: The Current Date is {0:d}. The {0:d} indicates where the date value goes in the label so that the skin developer can format the label text however he chooses. The “d” in the {0:d} indicates how the date is formatted if you look at the Green Hello.ascx Date label we use a capital D and it prints out a long string for the date. (For more information about string.format see the documentation.)
Our example project is now complete. You should be able to run the project and get back a skinned page displaying the current URL, date, and time. If you type any page name you should get a response from it with it’s URL. You can also go to the drop down and change the current skin and get a different look and feel with the same functionality. As we mentioned before this is a very simple example with only the bare neccesities to make this work. But with a little of imagination there is a lot of power to these techniques. If we extend the ASP.NET object model by adding a custom user object, for instance, we have a perfect vehicle for delivering personalization. Furthermore, add user editable content controls, with the appropriate security, of course, and you have a site which I.T. can fire and, for the most part, forget.

Figure 1: Ok, so this is not the most spectacular implementation of skinning, but all the pieces are here for you to build a skinnable site to meet your needs.
As currently scheduled, in a little over a year ASP.Net version 2.0 should be released with all of these features built in. What’s more, Visual Studio.Net will have complete designer support for it. While all that will be nice you will find that the model we have showed you here to still have plently of uses. From what we have seen in the early stages of ASP.Net 2.0 there are some limitations to its skinning engine that we believe this model overcomes. Also don’t worry about compatibility, this skinning engine works in ASP.Net 1, 1.1, and version 2. So you won’t be rebulding it when version 2 comes around.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。