继续,换肤功能的实现:master pages保持的是框架,但要做到真正的个性化,还得需要自己写代码。接下来,让我们看看内容的换肤。
以下代码来自于宝玉的BLOG,http://webuc.net/dotey/archive/2004/05/28/835.aspx。不过,是c#的,没有VB的,我改了一下。同时,讲得不细,不合一般入门级用户,我补充细一点。
(1) 打开一个Project
新建一个Themes的文件夹,然后加入两个文件:
·Login.ascx
其代码如下:
<P>登陆页的默认皮肤样式</P>
<P>用户名:<asp:TextBox id="Username" runat="server"></asp:TextBox></P>
<P>密 码:<asp:TextBox id="Password" runat="server" TextMode="Password" /></P>
<P><asp:Button id="LoginButton" runat="server" Text="登陆" /></P>
<P><asp:Label id="Result" runat="server" /></P>
·Login1.ascx
代码如下:
<P>登陆页的皮肤样式1</P>
用户名:<asp:TextBox id="Username" runat="server" />
密 码:<asp:TextBox id="Password" runat="server" TextMode="Password" />
<asp:Button id="LoginButton" runat="server" Text="登陆" /><asp:Label id="Result" runat="server" />
注意:VS自动生成的代码都可以删除掉,因为不需要。这里的代码只一个模板的作用。
(2) 新建一个Class的文件夹
加入一个SkinnedWebControl类,这是我们所有外观页面的基类
代码如下:
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.IO
Namespace WebUC.ThemeDemo.Controls
Public MustInherit Class SkinnedWebControl
'/ <summary>
'/ 换皮肤控件基类
'/ </summary>
Inherits WebControl
Implements INamingContainer 'ToDo: Add Implements Clauses for implementation methods of these interface(s)
Private skinFilenamePrv As String = Nothing
Protected Overrides Sub CreateChildControls()
Dim skin As Control
' 装载用户控件文件
skin = LoadSkin()
' 初始化控件和对控件绑定
InitializeSkin(skin)
Controls.Add(skin)
End Sub 'CreateChildControls
'/ <summary>
'/ 装载用户控件文件
'/ </summary>
'/ <returns></returns>
Protected Function LoadSkin() As Control
Dim skin As Control
' 用户控件文件默认放在Themes目录下
Dim skinPath As String = "Themes/" + skinFilenamePrv
' 是否定义了用户控件文件?
If skinFilenamePrv Is Nothing Then
Throw New Exception("必须定义SkinFilename属性,指定用户控件文件路径")
End If
' 通过Page.LoadControl(defaultSkinPath)方法,从用户控件文件中获取 UserControl 对象
Try
skin = Page.LoadControl(skinPath)
Catch
End Try
Return skin
End Function 'LoadSkin
'/ <summary>
'/ 初始化控件,并绑定控件数据
'/ </summary>
'/ <param name="skin"></param>
Protected MustOverride Sub InitializeSkin(ByVal skin As Control)
'/ <summary>
'/ 用户控件文件路径
'/ </summary>
Public Property SkinFilename() As String
Get
Return skinFilenamePrv
End Get
Set(ByVal Value As String)
skinFilenamePrv = Value
End Set
End Property
End Class 'SkinnedWebControl
End Namespace 'WebUC.ThemeDemo.Controls
这段代码的类图如下:
继承自WebControl基类,引入INameingContainer接口,防止重名。
重载CreateChildControls方法,此方法调用自定义LoadSkin方法装入皮肤。皮肤最后是使用Page.LoadControl(defaultSkinPath)方法,从用户控件文件中获取 UserControl 对象实现的。
再新类一个Login.vb的文件:
写入以下代码:
Imports System
Imports System.Web
Imports System.Web.UI.WebControls
Namespace WebUC.ThemeDemo.Controls
'/ <summary>
'/ 登陆控件,继承自SkinnedWebControl
'/ </summary>
Public Class Login1
Inherits SkinnedWebControl
Private skinFilename1 As String = "Login.ascx" ' 指定默认皮肤样式
Private username As TextBox ' 帐号输入框
Private password As TextBox ' 密码输入框
Private loginButton As Button ' 登陆按钮
Private result As Label
' 显示登陆结果
Public Sub New()
If SkinFilename Is Nothing Then
SkinFilename = skinFilename1
End If
End Sub 'New
'/ <summary>
'/ 重写InitializeSkin,初始化控件和对控件进行绑定
'/ </summary>
'/ <param name="skin"></param>
Protected Overrides Sub InitializeSkin(ByVal skin As System.Web.UI.Control)
' 查找ascx页中ID是username的textbox控件
username = CType(skin.FindControl("Username"), TextBox)
' 绑定数据
username.Text = "demo"
' 查找ascx页中ID是password的textbox控件
password = CType(skin.FindControl("Password"), TextBox)
' 绑定数据
password.Attributes.Add("value", "demo")
' 初始化Result控件
result = CType(skin.FindControl("Result"), Label)
' 找到登陆按钮
loginButton = CType(skin.FindControl("LoginButton"), Button)
AddHandler loginButton.Click, AddressOf LoginButton_Click ' 绑定登陆按钮的Click事件
End Sub 'InitializeSkin
'/ <summary>
'/ 响应登陆按钮事件
'/ </summary>
'/ <param name="sender"></param>
'/ <param name="e"></param>
Public Sub LoginButton_Click(ByVal sender As [Object], ByVal e As EventArgs)
If username.Text = "demo" And password.Text = "demo" Then
result.Text = "<font color='blue'>登陆成功!"
Else
result.Text = "<font color='red'>登陆失败,用户名密码不匹配!"
End If
End Sub 'LoginButton_Click
End Class 'Login
End Namespace 'WebUC.ThemeDemo.Controls
注意:
由于我们前面使用了Login.ascx用户控件。它会自动生成一个Login类。这个类是不需要的。可以删除它的代码。为了方便起见。在这儿,我们的类叫Login1,而不是Login。
这是类图。最重要的是这个类,重写了InitializeSkin方法。此方法中
' 找到登陆按钮
loginButton = CType(skin.FindControl("LoginButton"), Button)
AddHandler loginButton.Click, AddressOf LoginButton_Click ' 绑定登陆按钮的Click事件
这样的方式来处理控件和事件。此前这些代码由系统自动生成,现在则不得不新自来处理。这算是一种代价吧。
(3) 新建一个SkinTest.aspx页面。
代码如下:
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="SkinTest.aspx.vb" Inherits="hello.SkinTest"%>
<%@ Register TagPrefix="uc" Namespace="hello.WebUC.ThemeDemo.Controls" assembly="hello" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>SkinTest</title>
<meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<uc:Login1 runat="server" ID="Login" NAME="Login"/>
<uc:Login1 runat="server" SkinFilename="Login1.ascx" ID="Login1" NAME="Login1"/>
</form>
</body>
</HTML>
在这里,我们将展示一下新的用户控件方式:
用<%@ Register TagPrefix="uc" Namespace="hello.WebUC.ThemeDemo.Controls" assembly="hello" %>而不是<%@ Register TagPrefix="uc1" TagName="Login" Src="Themes/Login.ascx" %>。后一种方式可以由VS自动产生,前一种就不行了,又是手动。
注意:namespace那儿一定要跟类视图一致。
OK,看一下成果吧。
总结一下:
使用换肤功能:有得有失,得到的是更好的界面。失去的,是不得不手动写的代码和方便。