Dotnetnuke Portal的皮肤系统

(本帖内容应该是译文,参考下吧)

http://archive.cnblogs.com/a/759964/


概览

在Dotnetnuke Portal中应用皮肤系统的能力出现在应用程序的版本2中,它是一个被期待已久的增强功能。皮肤系统是指应用程序能够通过其设置而改变外观的能力。这种能力将应用程序的逻辑和用户界面或使用的对象分离开。Dotnetnuke Portal使用了三层面向对象的设计模式,用户界面在其中单独占用一层。这就使使用皮肤系统变得可行,并且应用程序依赖传递给页面的参数可以呈现独特的外观。在本文档中我们将看看皮肤系统的出色之处,并为你提供工具以开始创建你自己设计的皮肤方案。

Dotnetnuke Portal使用模板来达到实施皮肤系统的目的,使用模板使我们能够将应用程序的外观和布局属性同将内容显示给用户所需要的应用程序逻辑分开。我们为实现这个功能研究了很多不同的方法,最终,我们开发出了一个皮肤解决方案,此解决方案实现了在创建Dotnetnuke Portal站点时让网页设计师和程序工程师独立工作。由此,我们可以更快地部署Dotnetnuke Portal门户网站,更重要的是,通过实现功能完备的门户网站和建设目标而降低了相关费用。

通过在用户界面文件中使用tokens和identifiers来代表你可以选择提供在页面上的功能(dynamic functionality)是大多数皮肤系统通常采用的方式。Dotnetnuke Portal皮肤解决方案同样也采用了这种技术---当处理页面时,该技术使用合适的皮肤对象或控件替代token来为你提供token定义的功能。当你安装你的皮肤方案到应用程序中去时,就会完成上面提到的处理过程,我们会在下面进行讨论。

Dotnetnuke Portal中的皮肤系统允许你使用你喜欢的编辑器来创建你自己的皮肤方案,这为你---作为皮肤开发人员提供非常大的灵活性—你只需要遵循创建皮肤方案的规则就行,而使用什么工具则取决于你自己。而你可以创建.ascx或.html文件的皮肤方案。创建哪种类型的皮肤方案取决于你选择的编辑器以及你选择遵循的规则。允许你创建HTML或ASP.NET类型的皮肤方案是皮肤系统的刻意设计,以为皮肤方案的创建提供最大的灵活性并帮助建立起页面设计师和程序工程师之间的协作桥梁。Dotnetnuke Portal的核心开发团队认识到,基于HTML的开发人员多于ASP.NET的开发人员,因此允许使用HTML创建皮肤方案可以使更多的人利用Dotnetnuke Portal的皮肤系统功能而不需要学习新的技术,当然,学习如何将token放置在你的皮肤方案设计中除外。好了,你已经了解了一些皮肤系统为何如此架构的历史信息,现在让我们去看看皮肤系统的出色之处。

文件的组织
在你把你的皮肤方案安装到应用程序中之前,皮肤方案所包含的皮肤文件必须满足一定的规则。一旦满足了规则,你就可以使用Dotnetnuke Portal中的“文件管理员”上载一个包含你皮肤方案的,压缩的zip文件,而Dotnetnuke Portal则会转换你的皮肤文件,使之成为可用的门户皮肤。依你的需要,皮肤方案可以应用到门户的不同层面,可以应用到host层、Portal层、以及页面层。一旦你成功上载了皮肤方案,Dotnetnuke Portal将在Portals/_default/Skins目录下为皮肤方案文件创建一个目录。如果你查看Dotnetnuke Portal的文件结构的根结构,你将会注意到有一个Container的目录,你为皮肤创建的任何Container都将存放在这里。这些目录会在他们相应的皮肤ID中描述,而这些皮肤ID则用于唯一地确定在Dotnetnuke Portal中使用皮肤。这些设置都存放在一个皮肤表中,以使Dotnetnuke Portal在运行时间正确地确定装载什么皮肤。
页面的处理和皮肤的装载
Dotnetnuke Portal只使用一个页面来实现显示信息的功能,这个页面就是Default.aspx。这个页面是所有控件和皮肤元素的容器,Dotnetnuke Portal需要使用这些控件和皮肤元素来实现提交内容给门户用户的目的。你可以在Default.aspx页面中为其他的信息引用一个placeholder,因为Default.aspx页面的内容是非常基本的,如果你从IDE中查看页面的源代码就会明白。它包含一个需要装载之内容的placeholer,以及一些Dotnetnuke Portal使用的错误处理程序。当你看下面的代码,有一些更多的东西将会被“注射”在页面中,而不仅仅是页面的代码所显示的页面应有的外观。

<%@ Page CodeBehind="Default.aspx.vb" language="vb" AutoEventWireup="false"
Explicit="True" Inherits="Dotnetnuke Portal.Framework.CDefault" %>
<%@ Register TagPrefix="dnn" Namespace="Dotnetnuke Portal.Common.Controls"
Assembly="Dotnetnuke Portal" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
      <HEAD id="Head">
            <TITLE>
                  <%= Title %>
            </TITLE>
            <%= Comment %>
            <META NAME="DESCRIPTION" CONTENT="<%= Description %>">
            <META NAME="KEYWORDS" CONTENT="<%= KeyWords %>">
            <META NAME="COPYRIGHT" CONTENT="<%= Copyright %>">
            <META NAME="GENERATOR" CONTENT="<%= Generator %>">
            <META NAME="AUTHOR" CONTENT="<%= Author %>">
            <META NAME="RESOURCE-TYPE" CONTENT=" DOCUMENT">
            <META NAME="DISTRIBUTION" CONTENT=" GLOBAL">
            <META NAME="ROBOTS" CONTENT="INDEX, FOLLOW">
            <META NAME="REVISIT-AFTER" CONTENT="1 DAYS">
            <META NAME="RATING" CONTENT="GENERAL">
            <style id="StylePlaceholder" runat="server"></style>
            <asp:placeholder id="CSS" runat="server"></asp:placeholder>
            <asp:placeholder id="FAVICON" runat="server"></asp:placeholder>
            <script src="<%= Page.ResolveUrl("js/dnncore.js") %>"></script>
      </HEAD>
      <BODY ID="Body" runat="server" ONSCROLL="__dnn_bodyscroll()" BOTTOMMARGIN="0"
LEFTMARGIN="0"
            TOPMARGIN="0" RIGHTMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0">
            <noscript></noscript>
            <dnn:Form id="Form" runat="server" ENCTYPE="multipart/form-data"
style="height:100%;>
                  <asp:Label ID="SkinError" Runat="server" CssClass="NormalRed"
Visible="False"></asp:Label>
                  <asp:placeholder id="SkinPlaceHolder" runat="server" />
                  <INPUT ID="ScrollTop" runat="server" NAME="ScrollTop"
TYPE="hidden">
                  <INPUT ID="__dnnVariable" runat="server" NAME="__dnnVariable"
TYPE="hidden">
            </dnn:Form>
      </BODY>
</HTML>

你一定想知道所有这一切是如何工作的?当一个URL被请求,同时当用户进入Dotnetnuke Portal,请求就被检查,并通过一个数据库表来确定一个合适的皮肤。一旦确定了适当的皮肤,基于皮肤方案的定义,用户自定义的控件就会被“注射”到页面。实现这个功能的逻辑则定义在Admin/Skins/skin.vb文件中。下面的代码显示确定皮肤并装载它的逻辑。

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Init
        ’ CODEGEN: This call is required by the ASP.NET Web Form Designer.
        InitializeComponent()
        ’ set global page settings
        InitializePage()
        ’ process the current request(确定被请求的URL以及请求用户的身份)
        ManageRequest()
        ’ load skin control
        Dim ctlSkin As UserControl
        Dim objSkins As New UI.Skins.SkinController
        ’ skin preview
        If (Not Request.QueryString("SkinSrc") Is Nothing) Then
                PortalSettings.ActiveTab.SkinSrc = _
objSkins.FormatSkinSrc(QueryStringDecode(Request.QueryString("SkinSrc")) & ".ascx",
PortalSettings)
            ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc)
        End If

        ’ load assigned skin
        If ctlSkin Is Nothing Then
            If IsAdminControl() = True Or PortalSettings.ActiveTab.IsAdminTab _
Then
                Dim objSkin As UI.Skins.SkinInfo
                objSkin = objSkins.GetSkin(SkinInfo.RootSkin, _
PortalSettings.PortalId, SkinType.Admin)
                If Not objSkin Is Nothing Then
                    PortalSettings.ActiveTab.SkinSrc = _
objSkins.FormatSkinSrc(objSkin.SkinSrc, PortalSettings)
                Else
                    PortalSettings.ActiveTab.SkinSrc = ""
                End If
            ElseIf PortalSettings.ActiveTab.SkinSrc <> "" Then
                PortalSettings.ActiveTab.SkinSrc = _
objSkins.FormatSkinSrc(PortalSettings.ActiveTab.SkinSrc, PortalSettings)
            End If

            If PortalSettings.ActiveTab.SkinSrc <> "" Then
                ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc)
            End If
        End If

        ’ error loading skin - load default
        If ctlSkin Is Nothing Then
            ’ could not load skin control - load default skin
            If IsAdminControl() = True Or PortalSettings.ActiveTab.IsAdminTab _
Then
                PortalSettings.ActiveTab.SkinSrc = Common.Globals.HostPath & _
SkinInfo.RootSkin & glbDefaultSkinFolder & glbDefaultAdminSkin
            Else
                PortalSettings.ActiveTab.SkinSrc = Common.Globals.HostPath & _
SkinInfo.RootSkin & glbDefaultSkinFolder & glbDefaultSkin
            End If
            ctlSkin = LoadSkin(PortalSettings.ActiveTab.SkinSrc)
        End If

        ’ set skin path
        PortalSettings.ActiveTab.SkinPath = _
objSkins.FormatSkinPath(PortalSettings.ActiveTab.SkinSrc)

        ’ set skin id to an explicit short name to reduce page payload and make
it standards compliant
        ctlSkin.ID = "dnn"
        ’ add CSS links
        ManageStyleSheets(False)

        ’ add Favicon
        ManageFavicon()

        ’ add skin to page
        SkinPlaceHolder.Controls.Add(ctlSkin)

        ’ add CSS links
        ManageStyleSheets(True)

    End Sub

正如你在代码中看到的,你首先调用ManageRequest函数,它返回请求的URL以及关于谁发出资源请求的一些信息。这不仅让你知道被请求的URL,而且可以让你决定发出请求的用户是否可以访问他所请求的页面。让知道了发出请求的用户身份以及他所请求的资源后,你就可以从数据库中信息决定你所要使用的皮肤,以满足这个请求。由此,你创建一个新的用户控件对象ctlSkin并根据相关的信息查询数据库以决定为页面所装载的皮肤文件(.ascx文件),再利用创建的ctlSkin对象创建皮肤文件的用户控件实例。然后,你查看其他的属性并装载适当的级联样式表以及图标,如果你定义了这些元素的话。最后,绑定皮肤用户控件和属性到被请求的页面。此功能使Dotnetnuke Portal可以动态地重新安排应用程序的外观。你需要了解的是,因为数据库的调用以及让门户能够利用皮肤方案,这里有一些性能上的损失,但是,由于你的门户可以动态地改变其外观(它是Dotnetnuke Portal的关键特点),损失的性能也是非常值得的。
打包你的皮肤和容器(container)
你已经了解了将皮肤绑定到适当页面的过程,现在,让我们看看一个皮肤软件包的不同部分。软件包是文件和定义的编译后的实体,你使用软件包来包含你的文件以及告诉Dotnetnuke Portal当你安装它到门户中去时处理你的皮肤方案。一个皮肤或容器软件包包含下面的文件类型:

    *.htm,*.html文件:这些文件包含了布局,以表达你希望不同的皮肤对象如何被放置在你的页面设计中。这些文件将被转换成.ascx文件以安装到门户中去。
    *.ascx文件:它们是定义皮肤的用户控件,被预编译到皮肤系统需要的格式。
    *.css文件:这些文件包括级联样式表定义,你将用来定义在你的皮肤和容器中的文件
    *.gif, *.jpeg, *.jpg, *.png文件:带这些后缀的文件用来支持包含皮肤中的图像。
    *.*其它文件:你可以在你的软件包中使用任何其它的资源文件,但是这些必须是在host setting页面所设置允许的文件类型。

一个软件包可以包含多个皮肤和容器。这使你在一个软件包中创建一个网站所需要的所有皮肤。因为在运行时间,页面布局允许在不同的板块中放置内容模块,这是一个强大的功能,因为你肯定不想在一个网站的所有页面都使用相同的布局,但是你希望通用的图片和样式定义应用于整个网站。因此打包多个皮肤和容器的能力允许你为一个门户网站安装所有的皮肤。

你可以在皮肤软件包中使用一个manifest文件来定义包含在皮肤方案中的不同文件和元素。使用这个文件使你可以整合所有的文件到一个软件包中,并为Dotnetnuke Portal提供需要的指示以处理皮肤。虽然manifest文件会使你在创建皮肤方案的时候多花一些时间,但是它增强了安装过程的能力并允许在一个单一的步骤中有更好的控制。我们将在后面讨论使用manifest文件的好处,因为它是非常重要的控制机制,以控制你的皮肤方案的安装。
创建皮肤
你可以使用两种方法来创建皮肤。你根据你对特定技术的熟悉程度和个人喜好来选择使用的方法。可以使用HTML来创建皮肤,或者使用VS.NET来用.ascx创建皮肤。这样,你就可以在觉得舒服的环境中创建皮肤,并在创建皮肤时拥有灵活性。如果你是一个以前开发过传统网站的网页设计师,你也许喜欢使用你熟悉的编辑器用HTML创建你的皮肤方案;然而,如果你是一个程序工程师,你可能更愿意使用VS.NET和ASP.NET代码来创建你的皮肤方案。这两种方式基本上都是一样的,除了使用HTML的话会用到token,并且当你创建皮肤的时候你将会利用用户控件。当然,文件的后缀依你选择的方式不同而不同。

在最小的程度上,你需要为每个包开发至少两个皮肤,一个用于面对门户用户,一个用于管理模块。这样做的原因是面向用户的页面一般都有多个板块以适当地布置内容以满足需求,而管理区则只在页面显示一个单一的模块。因此,你需要构架两种不同的布局以充分地服务于每个不同的区域。

创建皮肤需要一些不同的步骤。你通过这些步骤的顺序并不重要,但是我们发现下面是你完成所有任务并使你的皮肤方案开始工作的适当方式。

要简化皮肤文件的开发并在以后有顺利的软件打包过程,我们建议你使用下面的文件夹结构:
\Skins
    \SkinName (这是你开发的包)
      ... (这是你创建可以分发的皮肤软件包zip文件的地方)
     \containers (这是一个确定用于皮肤软件包的容器文件的名字)
      ... (这将包括所有同你的容器关联的资源文件)
     \skins (这是一个确定用于皮肤软件包的皮肤文件的名字)
      ... (这将包括所有同你的皮肤关联的资源文件)
 

这为你开发你的皮肤方案提供了一个很容易的目录结构,你会发现此结构将帮助你简化为部署和安装皮肤到门户而创建软件包时的准备工作。在你设计你自己的皮肤方案时,皮肤系统有具有的自由形式的本质将为你提供一定程度的创作自由。网页设计师也许会以纯图形的方式创建网站的设计草稿,并在设计成熟后以切割图形的方式来满足需求。但网页设计师在设计皮肤时需要知道的一件事是任何皮肤都必须包括用户界面元素,它们可能是静态的元素如图片和文字,也可能是活动的元素如登录链接、导航和菜单系统、以及其它Dotnetnuke Portal需要的皮肤元素。

这就是页面设计师需要了解和一定会遇到的有关技术的地方,如何最有效地将页面的图形元素同其它元素分开并以HTML表达。HTML的布局同可以自由放置在页面不同位置的图片设计是完全不同的,将图片设计转换为HTML表达后会形成页面设计的最终布局。在这个阶段,你好要考虑和决定为网站确定适合什么样的显示解析度。如果你希望你的网站具有不管用户的显示解析度设置为如何都始终保持尺寸的不变,或能适应用户设置的显示解析度,你就应该在相应的项目上作出决定并做适当的调整。在下载的Dotnetnuke Portal软件包中有一些例子皮肤,你可以学习如何实现固定尺寸和适应尺寸的皮肤设计。

现在,你已经完成了设计,你需要开始动手创建你的皮肤方案了。象以前所提到的,你可以使用任何HTML编辑器,或VS.NET,甚至,如果你喜欢,选择使用记事本来为你的设计创建皮肤。你要记住的一件事是,你创建皮肤使用的HTML必须是well formed的,不然就会出现问题。这意味着你必须close掉任何你写的标注,这包括图片标注。图片标注通常都没有加close标注,所以你应该在图片标注的内容部分后加上符号/然后再结束标注。(<…./>)大多数现在的HTML编辑器将通过加上关闭的标注自动地为你处理这种情况,但你还是应该对你的工作进行检查以确保你创建的皮肤方案中没有因缺乏必要的标注而有臭虫。

既然谈到图片,我们就来看看关于在你的皮肤方案中图片的事情以及支持它们的文件。一般来说,你会将支持图片的文件和皮肤中的其它元素放在同一个文件夹中,但这不是必须的,你可以将它们放在任何你指定的文件夹中,你要关注的是确保它们的路径在装载过程后也是可用的。作为装载过程的一部分,皮肤系统将为你的图片添加一个明确指示的路径。这是为了在运行时间保证皮肤方案的性能。皮肤系统将添加/Portals/_default/YourSkinName到你指定的图片文件路径之前。当你为网站创建内容的时候你需要当心的一件事情是,上面提到的路径是否在开发阶段和实际运行阶段是不一样的,如果是这样的话,你的图片路径就是错误的而图片也不能正确地显示。

发生这种错误的例子是假如你在你的本地计算机上创建一个网站,它的虚拟目录是http://localhost/VirtualDirectory,然后你将之部署在实际运行的位置http://www.YourDomain.com。完成这个任务的最容易的方法是备份你的本地数据库,然后在运行位置的数据库中restore它,再将你的其它文件ftp到运行位置,对Portal Alias和web.config文件进行适当的配置。但是当你完成这个移植后,你将发现你的图片不能正常工作了。如果你遇到这样的问题,你有两种方法来解决,你可以重新安装皮肤,覆盖以前的皮肤;或者你可以直接修改皮肤文件依纠正错误的图片路径。在皮肤方案的开发中,最好的事情是对上面可能出现的问题作一个周全的准备和计划。

现在,你已经有了你的设计方案,以及一个你的皮肤如何架构的好主意,你需要将皮肤对象放置在皮肤文件的适当位置。这样Dotnetnuke Portal将知道在什么地方插入不同的内容板块、门户元素以及导航对象。依赖于你创建皮肤使用的方法,这个过程将有所不同。假如你使用ASCX皮肤,你就需要在你的皮肤中指定@Register以及用户控件标注。例如:<dnn:Login runat=”server” id=”dnnlogin”>,此语句会将一个Login用户控件放置在你的皮肤文件中指定该控件的位置上。假如你使用HTML皮肤,那你只需要为相应的皮肤元素简单地包括一个token。所以,对于HTML皮肤,你只是在你需要的地方加上一个[Login]token,而皮肤系统将在装载并解释皮肤的时候将[Login]token替换为实际的控件。每一个不同的皮肤对象都有其唯一的功能,你必须了解它们以创建一个具有功能的皮肤。下面的表列出了所有这些对象以及它们的目的,同时提供了如何在两种方法中使用它们的例子。

Table 13-1: Skin Objects 
Token     Control     Description 
[SOLPARTMENU]    < dnn:SolPartMenu runat=" server" id=" dnnSolPartMenu">    Displays the hierarchical navigation menu (formerly [MENU]).
[LOGIN]    < dnn:Login runat=" server" id=" dnnLogin">    Dual state control — displays "Login" for anonymous users and "Logout" for authenticated users.
[BANNER]    < dnn:Banner runat=" server" id=" dnnBanner">    Displays a random banner ad.
[BREADCRUMB]    < dnn:Breadcrumb runat=" server" id=" dnnBreadcrumb">    Displays the path to the currently selected tab in the form of Page-Name1 > PageName2 > PageName3.
[COPYRIGHT]    < dnn:Copyright runat=" server" id=" dnnCopyright">    Displays the copyright notice for the portal.
[CURRENTDATE]    < dnn:CurrentDate runat=" server" id=" dnnCurrentDate">    Displays the current date.
[DOTNETNUKE PORTAL]    < dnn otnetnuke Portal runat=" server" id=" dnnDotnetnuke Portal">    Displays the Copyright notice for Dotnetnuke Portal (not required).
[HELP]    < dnn:Help runat=" server" id=" dnnHelp">    Displays a link for Help, which will launch the user’s e-mail client and send mail to the portal Administrator.
[HOSTNAME]    < dnn:HostName runat=" server" id=" dnnHostName">    Displays the Host Title linked to the Host URL.
[LINKS]    < dnn:Links runat=" server" id=" dnnLinks"&gt;    Displays a flat menu of links related to the current tab level and parent node. This is useful for search engine spiders(十字瞄准器) and robots.
[LOGO]    < dnn:Logo runat=" server" id=" dnnLogo">    Displays the portal logo.
[PRIVACY]    < dnn rivacy runat=" server" id=" dnnPrivacy">    Displays a link to the Privacy Information for the portal.
[SIGNIN]    < dnn:Signin runat=" server" id=" dnnSignin">    Displays the signin control for providing your username and password.
[TERMS]    < dnn:Terms runat=" server" id=" dnnTerms">    Displays a link to the Terms and Conditions for the portal.
[USER]    < dnn:User runat=" server" id=" dnnUser">    Dual state control — displays a "Register" link for anonymous users or the user’s name for authenticated users.
[CONTENTPANE]    <div runat=" server" id=" ContentPane">    Injects a placeholder for module content.

上面的皮肤对象在你创建你的皮肤方案时是可以用的,还有一些其它的对象,用于创建容器。你可以把这些对象放在皮肤的任何地方并控制门户元素的布置。你也许在考虑并不是所有上面提供的对象你都想在你的皮肤上使用,实际上你也可以不放置你不需要的对象。你需要知道的是,每个皮肤必须至少要有一个ContentPane,而且它必须被标识为content pane,否则模块不能正确地显示。

在皮肤的创建中,需要用到一些属性。这些属性将定义在skin.xml文件中或manifest文件中。通过这些文件,你告诉Dotnetnuke Portal你想如何利用不同的皮肤对象。例如,你希望在你的皮肤中,导航菜单以水平的方式布置。这将在skin.xml文件中进行设置,这样皮肤系统就知道如何按你的要求正确地放置导航菜单在你的皮肤中。下面的表列出了你可以设置的属性。
Table 13-2: Skin Attributes 
Token     Attribute     Default     Description 
[SOLPARTMENU]    separatecss    true    CSS defined in a style sheet (values: true, false)
     backcolor    #333333    Background color
     forecolor    white    Forecolor of menu item when selected
     highlightcolor    white    Color of top and left border to give a highlight effect
     iconbackground color    #333333    Background color in area where icon is displayed
     selectedb ordercolor         Color of border surrounding selected menu item
     selectedcolor    #CCCCCC    Background color of menu item when selected
     selectedforecolor    white    Forecolor of menu item when selected
     display    horizontal    Determines how the menu is displayed, horizontal or vertical (values: vertical, horizontal)
     menubarheight    16    Menu bar height in pixels
     menuborderwidth    1    Menu border width in pixels
     menuitemheight    21    Menu item height in pixels
     forcedownlevel    false    Flag to force the downlevel menu to display (values: true, false)
     moveable    false    Flag to determine if menu can be moved (values: true, false)
     iconwidth    0    Width of icon column in pixels
     Menueffects shadowcolor    dimgray    Color of the shadow
     menueffectsmouse outhidedelay    500    Number of milliseconds to wait until menu is hidden on mouse out (0 = disable)
     mouseouthide delay    1    Number of milliseconds to wait until menu is hidden on mouse out (0 = disable)
     menueffectsmouse overdisplay    Highlight    Adjusts effect when mouse moves over menu bar item (values: Outset, Highlight, None)
     menueffects mouseoverexpand    true    Makes menu expand on mouse-over (unlike any menu found within the Windows environment) (values: true, false)
     menueffectsstyle    filter:progid: DXImage Transform .Microsoft .Shadow(color =’DimGray’, Direction=135, Strength=3) ;    IE-only property for SubMenu styles and transitions
     fontnames    Arial     
     fontsize    12     
     fontbold    false     
     Menueffects shadowstrength    3    Determines how many pixels the shadow extends
     Menueffects menutransition    None    Determines which direction the shadow will fall (values: None, AlphaFade, AlphaFadeBottomRight, Barn, Blinds, Checkerboard, Constant-Wave, Fade, GradientWipe, Inset, Iris, RadialWipe, Random, RandomBars, Slide, Spiral, Stretch, Strips, Wave, Wheel, Zigzag)
     menueffectsmenu transitionlength    0.3    Number of seconds the transition will take
     Menueffects shadowdirection    Lower Right    Determines which direction the shadow will fall (values: None, Top, Upper Right, Right, Lower Right, Bottom, Lower Left, Left, Upper Left)
     menucontainer cssclass    MainMenu_ Menu Container    Menu Container CSS Class
     menubarcssclass    MainMenu_ MenuBar    Menu Bar CSS Class
     menuitemcssclass    MainMenu_ MenuItem    Menu Item CSS Class
     menuiconcssclass    MainMenu_ MenuIcon    Menu Icon CSS Class
     menuitems elcssclass    MainMenu_ MenuItemSel    Menu Item CSS Class for mouse-over
     menubreakcssclass    MainMenu_ MenuBreak    Menu Break CSS Class
     submenucssclass    MainMenu_ SubMenu    SubMenu CSS Class
     menuarrowcssclass    MainMenu_ MenuArrow    Menu Arrow CSS Class
     menuroot arrowcssclass    MainMenu_ MenuRoot Arrow    Menu Root Arrow CSS Class
     forcefullmenulist    false    Displays the full menu as an indented list of normal hyperlinks (like a sitemap) {true|false}
     useskinpath arrowimages    false    Use arrow images located in the skin and not those in the /images folder {true|false}
     userootbread crumbarrow    true    Use a breadcrumb arrow to identify the root tab that is listed in the breadcrumb ArrayList {true|false}
     usesubmenu breadcrumbarrow    false    Use a breadcrumb arrow to identify the submenu tabs that are listed in the breadcrumb ArrayList {true|false}
     Rootbread crumbarrow         Image used for root-level menu breadcrumb arrows - i.e., file.gif
     submenubread crumbarrow         Image used for submenu menu breadcrumb arrows - i.e., file.gif
     usearrows         Use arrows to indicate child submenus
     downarrow    menu_ down.gif    Arrow image used for downwardfacing arrows indicating child submenus
     rightarrow    bread crumb.gif    Arrow image used for right-facing arrows indicating child submenus
     level    Root    Root level of the menu in relationship to the current active tab {Root|Same|Child}
     rootonly    false    Indicator to turn off submenus {true|false}
     rootmenuitem breadcrumb cssclass         CSS class used for root menu items when they are found in the breadcrumb ArrayList
     submenuitem breadcrumb cssclass         CSS Class used for submenu items when they are found in the breadcrumb ArrayList
     Rootmenuitem cssclass         CSS class used for root menu items
     rootmenuitem activecssclass         CSS class used for root menu items when they are the active tab
     submenuitem activecssclass         CSS class used for submenu items when they are the active tab
     rootmenuitem selectedcssclass         CSS class used for root menu items when they are moused-over
     submenuitem selectedcssclass         CSS Class used for submenu items when they are moused-over
     separator         The separator between root-level menu items. This can include custom skin images, text, and HTML (i.e., <![CDATA[&nbsp;<img src=" file.gif">&nbsp;]]>
     separatorcssclass         CSS class used for the root-level menu item separator
     Rootmenuitem lefthtml         HTML text added to the beginning of the root menu items
     rootmenuitem righthtml         HTML text added to the end of the root menu items
     Submenuitem lefthtml         HTML text added to the beginning of the submenu items
     Submenuitem righthtml         HTML text added to the end of the submenu items
     tooltip         Tooltips added to the menu items. These come from the tab object properties, which are filled from the tabs table {Name|Title|Description}
     leftseparator         The separator used just before a root-level menu item. A use for this might be a left edge of a tab image, for example.
     rightseparator         The separator used just after a root-level menu item. A use for this might be a right edge of a tab image, for example.
     Leftseparator active         The separator used just before an active root-level menu item
     Rightseparator active         The separator used just before an active root-level menu item
     leftseparator breadcrumb         The separator used just before a root-level menu item found in the breadcrumb ArrayList
     rightseparator breadcrumb         The separator used just before a root-level menu item found in the breadcrumb ArrayList
     leftseparator cssclass         CSS class used for leftseparator
     rightseparator cssclass         CSS class used for rightseparator
     leftseparator activecssclass         CSS class used for leftseparatoractive
     rightseparator activecssclass         CSS class used for rightseparatoractive
     leftseparatorbread crumbcssclass         CSS class used for leftseparatorbreadcrumb
     rightseparator breadcrumbcssclass         CSS class used for rightseparator-breadcrumb
     menualignment    Left    Alignment of the menu within the menu bar {Left|Center|Right|Justify}
     cleardefaults    false    If true, this value will clear/empty the default color settings of the menu so that they can be left empty and not just overridden with another value
[LOGIN]    Text    Login    The text of the login link
     CssClass    OtherTabs    The style of the login link
     LogoffText    Logoff    The text for the logoff link
[BANNER]    BorderWidth    0    The border width around the banner
[BREADCRUMB]    Separator    bread crumb.gif    The separator between breadcrumb links. This can include custom skin images, text, and HTML (i.e., <![CDATA[&nbsp;<img src=" file.gif">&nbsp;]]>
     CssClass    SelectedTab    The style name of the breadcrumb links
     RootLevel    1    The root level of the breadcrumb links. Valid values include:
-1 — show word "Root" and then all breadcrumb tabs
0 — show all breadcrumb tabs
n (where n is an integer greater than 0)
— skip n breadcrumb tabs before displaying
[COPYRIGHT]    CssClass    SelectedTab    The style name of portal copyright link
[CURRENTDATE]    CssClass    SelectedTab    The style name of date text
     DateFormat    MMMM dd, yyyy    The format of the date text
[DOTNETNUKE PORTAL]    CssClass    Normal    The style name of Dotnetnuke Portal portal engine copyright text
[HELP]    CssClass    OtherTabs    The style name of help link
[HOSTNAME]    CssClass    OtherTabs    The style name of Host link (Powered By xxxxxxxxx)
[LINKS]    CssClass    Command Button    The style name of the links
     Separator    &nbsp;& nbsp;    The separator between links. This can include custom skin images, text, and HTML (i.e., <![CDATA[&nbsp;<img src=" file.gif">&nbsp;]]> .
     Alignment    Horizontal    The links menu style ("Horizontal" or "Vertical")
     Level    Same    Determines the menu level to display ("Same", "Child", "Parent", "Root")
[LOGO]    BorderWidth    0    The border width around the logo
[PRIVACY]    Text    Privacy Statement    The text of the privacy link
     CssClass    OtherTabs    The style name of privacy link
[SIGNIN]               
[TERMS]    Text    Terms of User    The text of the terms link
     CssClass    OtherTabs    The style name of terms link
[USER]    Text    Register    The text of the register/user link
     CssClass    OtherTabs    The style name of register/user link
[CONTENTPANE]    ID    Content Pane    The content pane key identifier to be displayed in the user interface and stored in the database.

你已经看到,每个皮肤对象都有一些属性。这使创建皮肤的过程变得稍稍有点复杂,但是你学会使用每个皮肤对象的属性是非常重要的,这样可以充分利用Dotnetnuke Portal皮肤系统提供的灵活性和强大功能。你可以看到菜单控件的属性占据了上面表中大部分的空间(有很多)---它显示了Dotnetnuke Portal所使用的菜单系统的灵活性。你要了解的是,菜单系统是一个不断开发和完善的控件,这意味这会有不断的版本更新,你现在看到的属性或许是不完整的。你应该查看随下载一起的菜单系统文档确保你知道所有可能的选择。

皮肤系统支持皮肤对象有多个实例,因此你可以在你的皮肤中定义多个菜单或其它实例。你当然必须给每个实例一个唯一的名字,比如,你可以定义一个叫[MENU]的菜单对象,另外还可以定义一个叫[MENU:1]的菜单对象。这种能力对你的内容区域很重要,因为你可能希望在你的皮肤中有多于一个的内容区。你必须至少定义一个叫[ContentPane]的板块,但是你可能希望还有其它区域以组织你的内容,由此你可以象上面的例子一样使用名字来定义不同的实例,只是把上面的菜单对象换成内容对象就好了。

你可以依上面的表为你的每个皮肤对象设置属性。每个皮肤对象都支持属性并且你可以在定义皮肤对象的时候定义它们。例如,在前面定义Login控件的例子里,你可以为你的控件设定文字,如<dnn:Login runat=”server” id=”dnnLogin” Text=”Signin”/>。这个例子仅对你用ascx开发皮肤的时候有用。假如你是使用HTML的方式来开发你的皮肤,则你必须将属性设置包括在manifest文件中。

一个皮肤软件包也许会包含一个全局属性,它定义在一个名叫”skin.xml(或”container.xml”---对于容器)的文件中,此文件将应用在你的皮肤文件中。你可以使用一个叫着“YourSkinFile.xml”的文件,用一个皮肤中定义的属性规范重新定义全局皮肤属性规范。皮肤系统的Uploader将用HTML表示的皮肤文件里的信息合并皮肤属性以创建一个ASCX皮肤文件。下面的代码是一个manifest文件的一部分,描述属性的设置。
<Objects>
      <Object>
            <Token>[LOGIN]</Token>
            <Settings>
                  <Setting>
                        <Name>Text</Name>
                        <Value>Signin</Value>
                  </Setting>
            </Settings>
      </Object>
</Objects>

正如你看到的那样,在上面例子中的代码完成了在ASCX例子中同样的事情,而且还能使另外的属性和表达层分开。这样的方式会使你创建的HTML皮肤文件非常清晰和容易理解,因为在HTML代码中不会充斥着需要你另外关心的属性代码。

你应该注意到在皮肤文件中的皮肤对象的定义是一对一的(即菜单定义为MENU),同时在skin.xml中则有不同实例的属性定义,这对每个命名了的实例都是一样的。例如,你想在皮肤中包括一个垂直的和水平的菜单系统,于是,你在皮肤中定义一个命名为[MENU:1]和[MENU:2]的菜单实例,然后在skin.xml文件中分别为它们创建不同的属性定义。

当你使用HTML创建皮肤并定义了多个ContentPanes,你将需要在属性文件中定义其”ID”属性。这将在你管理门户的时候使Dotnetnuke Portal正确地确定适当的板块以插入你的模块。由此,你也有机会为你需要的不同板块添加“友好描述”。例如,在下面的代码中,你将看到如何在manifest文件中定义板块的ID。你可以为你设计中的不同板块ID定义你需要数量的文件节点。

<Objects>
      <Object>
            <Token>[CONTENTPANE:1]</Token>
            <Settings>
                  <Setting>
                        <Name>ID</Name>
                        <Value>RightPane</Value>
                  </Setting>

            </Settings>

      </Object>
</Objects>

正如你看到的,你可以有一个名字叫RightPane的板块,并在运行时间显示给用户。你还可以定义一个LeftPane和NavigationPane;只要你的设计需要。这显示了皮肤系统的一些灵活性,因为你可以利用需要的一些板块来完成你的设计。皮肤系统允许你创建一个自己的布局来利用Dotnetnuke Portal应用程序。通过在你的皮肤和属性文件中利用代码的组合,你可以创建几乎任何你可以想象的皮肤设计。

当你理解了设计皮肤方案的方式,我们现在来看看如何为你的皮肤创建级联样式表修饰(CSS文件)。CSS文件需要被编写并同你的其它资源文件一起保存在你的皮肤目录里。皮肤系统可以使用外部的样式表定义,这使你可以将你的样式定义同你的皮肤分开,并使用可以应用于不同层次上的css文件。这意味着你不一定必须自己动手为你的皮肤创建一个CSS文件,因为你可能使用一个已有的CSS文件来为你定义样式,但为了是你创建的皮肤方案是独一无二的,你也许希望自己为皮肤设计创作一个样式表定义。在门户系统中,是以自然的层级结构来组织多个样式表的,因此,一个样式表定义可能会覆盖另外一个样式表定义。在存在多个样式表定义情况下,那个会起作用?这里有一个非常清楚的优先级顺序。下面的列表总结了样式表的级联顺序,前面的项目会覆盖后面的:

    模块级: 在模块级的样式表定义用于单个模块的样式。
    缺省: 这是host层的缺省的样式表,文件是default.css。
    皮肤级: 你为你的皮肤方案可以创建和应用这些样式。
    容器级: 每个容器都有一个对它是唯一的样式定义。
    门户级: 由门户管理员定义的定制样式,其文件为portal.css。
你可以有两种方式为你的皮肤定义样式文件。你可以创建一个名叫skin.css的CSS文件并将之放在皮肤的目录里。这个样式文件将应用于皮肤包中所有的皮肤。你也可以将你的CSS文件命名为skinname.css,则它将应用于有相同名字的皮肤文件。你可以写任何你需要的样式定义,但是,至少你应该用作为皮肤方案一部分的,你自己定义的样式覆盖缺省的样式定义。
现在,你已经创建了需要的皮肤,接着你要做的事情是制作一副图片,这样你可以在预览画廊里显示你的皮肤的样子。要做到这点,你需要创建一个具有jpg后缀的高质量图片,而且它的名字必须同你的皮肤文件一样。例如,假如你的皮肤文件是mySkin.ascx,你的图片文件的名字就该是mySkin.jpg。这个相同的概念同样应用于容器的创建中。
当然,最后一步就是打包皮肤文件以在未来分发。这个打包的文件必须是*.zip的压缩文件。你可以使用很多第三方的压缩工具,如winzip或Windows XP内建的工具。在压缩你的文件包时,一个需要当心的问题是在第一层压缩目录和你的皮肤文件之间没有隐藏的目录。这是经常发生的错误操作,并会导致上载过程失败。
在多数的情况下,你都会希望将一组完整的皮肤文件和容器文件打包在一个分发包里。为了做到这点,你需要将你的容器文件打包在一个压缩的*.zip文件中,并取名为containers.zip。同样,你必须打包你的皮肤文件在一个*.zip文件中并命名为skins.zip。然后你将上面两个打包文件再打包成一个单独的*.zip文件,文件名则同皮肤文件一样。这样,你的用户就可以通过一个单一的文件安装所有需要的皮肤。
容器制作
现在,我们来看看为你的皮肤制作相关容器的过程。容器是应用在容器层的基本皮肤定义。制作容器的过程同创建皮肤的过程非常相似,只有一个唯一的不同是对于一个容器而言可用的属性和皮肤对象。
制作容器的一个需要是,你必须使用一个Actions控件,以使你可以能管理模块的功能。Actions控件使将模块功能绑定到门户架构的机制。它实际上是一个模块需要的用户定义控件,以完成模块的内部工作。每个模块都能定义自己的行为,但是一般来说你需要的功能是添加和编辑模块的内容,以及可以在页面的不同板块移动(门户级功能),并且能编辑模块的设置,如许可、标题等等。你需要满足必须的最少行为,当然也可以创建更多的行为以提供模块独特的功能。关于增加自己定义行为的完整描述,请参考我们的其它专题。缺省的行为菜单使用了SolPartActions控件,它的功能是当你悬停在模块的编辑图标上时提供一个弹出菜单。这个菜单只能在最新版本的浏览器中正常工作,并在使用IE 6+时非常可靠。如果你使用老的浏览器版本的话,有一个低级的控件版本来提供一个下拉框。
正如我们所讲过的,你需要将你的皮肤和容器设计配合起来,以为用户提供一种很自然和一致的感觉。当你将它们联系在一起进行开发时(即使它们实际上是不同的实体),这个使它们达到配合一致的目标的过程也许会稍稍变得更容易一些。现在你已经有了基础,让我们看看一个容器的manifest文件的例子。Manifest文件是我们定义皮肤对象属性的地方。为了简化操作并提供更精细的控制,我们提供了板块级皮肤的概念。板块级皮肤只能在皮肤设计者创建皮肤时的设计时间配置。它包括使用一些定制的属性,这些属性被包括在形成板块的标注代码中。我们使用ContainerType, ContainerName, 以及ContainerSrc属性来定义一个特定的容器,而这个容器可由所有可“注射”到板块中的模块使用。为了做到这点,容器必须放置在特定的位置,否则,缺省的容器就会被显示出来。下面的代码显示此概念的一个基本例子。
<Objects>
      <Object>
            <Token>[CONTENTPANE:1]</Token>
            <Settings>
                  <Setting>
                        <Name>ID</Name>
                        <Value>LeftPane</Value>
                  </Setting>
                  <Setting>
                        <Name>ContainerType</Name>
                        <Value>G</Value>
                  </Setting>
                  <Setting>
                        <Name>ContainerName</Name>
                        <Value>DNN</Value>
                  </Setting>
                  <Setting>
                        <Name>ContainrSrc</Name>
                        <Value>standard.ascx</Value>
                  </Setting>
            </Settings>
      </Object>
</Objects>
在这个例子中看到,你可以为皮肤设计的每个区域定义一个标准的容器。你也可以在门户层设置缺省的容器,它则会应用到所有被添加到门户的新模块。前面的例子使加入模块的过程更快,因为你不需要在加入模块后设置其容器。

正如你看到的,在我们的门户系统中,容器的功能同皮肤一样有用,你可以使用此技术使你的页面变得与众不同。下面的表陈列出在你开发容器时你可以使用的皮肤对象。
Table 13-3: Container Skin Objects 
Token     Control     Description 
[SOLPARTACTIONS]    < dnn:SolPartActions runat= " server" id=" dnnSolPart Actions">    Pop-up module actions menu (formerly [ACTIONS])
[DROPDOWNACTIONS]    < dnn ropDownActions runat=" server" id=" dnnDrop DownActions">    Simple drop-down combo box for module actions
[LINKACTIONS]    < dnn:LinkActions runat= " server" id=" dnnLinkActions">    Links list of module actions
[ICON]    < dnn:Icon runat=" server" id=" dnnIcon">    Displays the icon related to the module
[TITLE]    < dnn:Title runat=" server" id=" dnnTitle">    Displays the title of the module
[VISIBILITY]    < dnn:Visibility runat=" server" id=" dnnVisibility">    Displays an icon representing the minimized or maximized state of a module
[PRINTMODULE]    < dnn rintModule runat= " server" id=" dnn PrintModule ">    Displays a new window with only the module content displayed
[CONTENTPANE]    <div runat=" server" id=" ContentPane">    Injects a placeholder for module content

你可以看到,在容器的制作中,你可以使用一些同在创建皮肤时相同的功能,但是这里仍提供一些其它的对象,这些对象在一个页面层没有什么用,但是在模块层却是非常重要的。这些是一些非常有用的对象,它们真正能够增加对你的模块和容器的使用,因此,你值得花一些时间来熟悉这些皮肤对象。下面的表涵盖了你可以用于制作容器的皮肤对象和它们的属性。
Table 13-4: Container Skin Object Attributes 
Token     Attribute     Default     Description 
[SOLPARTACTIONS]               
[DROPDOWNACTIONS]               
[LINKACTIONS]               
[ICON]    BorderWidth    0    The border width around the icon
[TITLE]    CssClass    Head    The style name of title
[VISIBILITY]    BorderWidth    0    The border width around the icon
     MinIcon    min.gif    The custom min icon file located in the skin file
     MaxIcon    max.gif    The custom max icon file located in the skin file
[PRINTMODULE]    PrintIcon    print.gif    The custom print icon file located in the skin file
[CONTENTPANE]    ID    Content Pane    The content pane key identifier to be displayed in the user interface and stored in the database

现在,我们已经定义了对象和其属性,让我们看看一个例子容器。下面的代码显示来自缺省安装的DNN-Blue容器。你会看到该容器利用了一些我们在前面讨论过的相同的属性。
<TABLE class=" containermaster_blue" cellSpacing="0" cellPadding="5" align=" center"
border="0">
        <TR>
          <TD class=" containerrow1_blue">
            <TABLE width="100%" border="0" cellpadding="0" cellspacing="0">
              <TR>
                <TD valign=" middle" nowrap><dnn:ACTIONS runat=" server"
id=" dnnACTIONS" /></TD>
                <TD valign=" middle" nowrap><dnn:ICON runat=" server" id=" dnnICON"
/></TD>
                <TD valign=" middle" width="100%" nowrap>&nbsp;<dnn:TITLE
runat=" server" id=" dnnTITLE" /></TD>
                <TD valign=" middle" width="20" nowrap><dnn:VISIBILITY
runat=" server" id=" dnnVISIBILITY" /></TD>
               </TR>
             </TABLE>
           </TD>
         </TR>
         <TR>
           <TD id=" ContentPane" runat=" server" align=" center"></TD>
         </TR>
         <TR>
           <TD>
             <HR class=" containermaster_blue">
             <TABLE width="100%" border="0" cellpadding="0" cellspacing="0">
               <TR>
                 <TD align=" left" valign=" middle" nowrap><dnn:ACTIONBUTTON1
runat=" server" id=" dnnACTIONBUTTON1" CommandName=" AddContent.Action"
DisplayIcon=" True" DisplayLink=" True" /></TD>
                 <TD align=" right" valign=" middle" nowrap><dnn:ACTIONBUTTON2
runat=" server" id=" dnnACTIONBUTTON2" CommandName=" SyndicateModule.Action"
DisplayIcon=" True" DisplayLink=" False" />&nbsp;<dnn:ACTIONBUTTON3 runat=" server"
id=" dnnACTIONBUTTON3" CommandName=" PrintModule.Action" DisplayIcon=" True"
DisplayLink=" False" />&nbsp;<dnn:ACTIONBUTTON4 runat=" server" id=" dnnACTIONBUTTON4"
CommandName=" ModuleSettings.Action" DisplayIcon=" True" DisplayLink=" False" /></TD>
               </TR>
             </TABLE>
           </TD>
         </TR>
       </TABLE>
       <BR>

在上面例子中是一个简单的容器,它是门户的蓝色主题的一个组成部分。你也许已经注意到在上面的例子里使用ASCX的方式。假如你想使用此容器,你需要为每个我们增加的控件添加一个Register directive。
小结
本部分带你了解了一些如何在Dotnetnuke Portal中创建自己的皮肤的基础知识。基本上假如你能使用HTML设计和编写代码的话,同时能遵从皮肤系统实施的一些简单的规则,那么你就可以创建很漂亮的设计。很多免费的和商务应用的皮肤你都可以做为参考。在Dotnetnuke Portal网站以及Dotnetnuke Portal目录中的资源站点上有相当多的例子。我们建议你下载这些例子,并使用在本文档中学习到的知识,一会功夫,你就可以创建高质量的皮肤。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值