关于一些DNN样式的观点曾在以前文章提到过, 比如DNN默认核心CSS继承关系解析, DNN Style Sheet简要总结, DNN性能优化建议, 加速DNN的新举措等等都讲述如何管理和优化DNN本身的CSS样式文件, 这些文章都可归结为一个结论: 理解DNN的样式继承关系是设计和开发皮肤(Skin) 和模块(Module)必备的, 也是优化DNN网站必须了解的.大家有兴趣深入了解DNN的核心机制不妨回头看看这些文章. 本文将从另外一个角度来说说DNN的样式, 那就是如何在DNN模块级别上动态添加样式文件.
如果你了解或开发过DNN模块, 那你应该都会碰到如何在DNN模块添加样式这一问题, DNN在加载模块时默认会在目标模块根目录寻找是否module.css这一样式文件, 如果存在则将添加到页面样式控件, 其位置位于其他样式之前(比如Portal样式, 皮肤样式, 容器样式), 但位于默认全局样式(default.css)之后, 而地位则相反(我想大家应该都了解, 因为位置在后的样式将覆盖其之前的样式), 更多分析请查看DNN默认核心CSS继承关系解析. 其继承应该类似于下图:
<link id="_Portals__default_" rel="stylesheet" type="text/css"
href="/Portals/_default/default.css" />
<link id="_DesktopModules_Blog" rel="stylesheet" type="text/css"
href="/DesktopModules/Blog/module.css" />
<link id="_Portals__default_Skins_DNN_Minimal_" rel="stylesheet" type="text/css"
href="/Portals/_default/Skins/DNN-Minimal/skin.css" />
<link id="_Portals_0_Containers_DNN_10_0_" rel="stylesheet" type="text/css"
href="/Portals/0/Containers/DNN.10.0/container.css" />
<link id="_Portals_0_" rel="stylesheet" type="text/css" href="/Portals/0/portal.css" />
反之查找不到module.css则不做任何添加样式操作. 有时开发的模块比较庞大, 包含很多用户控件, 甚至可能会支持主题更换功能或兼容浏览器, 显然单一module.css是不能满足我们的要求的. 此时我们也许需要添加除了module.css之外的样式文件, 甚至为了开发和管理的方便也不再使用module.css, 转而新建包含比较有意义名称的样式文件, 比如manage.css或settings.css等等, 到此问题出来, 如何在DNN模块级别上动态添加定制的样式文件呢? 大家也许会马上说, 那就直接在用户控件顶头声明即可呗(这种方式需要注意的一点是路径问题), 是的, 这是最快捷和最简单的方式, 不过便捷也带来就是一些"小" 问题, 比如样式冗余重复(因为也许一个页面会存在两个同样的模块), 样式掺杂在页面Body中间(这对于UI前端开发人员来说无疑是一种噩梦, 样式本应声明在页面Header内). 那如何和解决, 有没有更好的添加方式呢? 也许存在更优秀的解决方案, 不过今天在此分享的是一个比较轻量级的替代方式, 欢迎大家拍砖.
其实如果细你读过DNN代码或根目录下的default.aspx.cs, 我想你也许已经找到这种方式甚至正在用类似方式注入样式文件. :) 不错那就是借助DNN核心注入样式的代码并迁移到模块级上使用, DNN核心存在一个类继承自PageBase的CDefault(更多信息:DNN核心API简述), 它存在两个重载的方法负责添加样式文件到页面Header内:
'insert the style
Public Sub AddStyleSheet(ByVal id As String, ByVal href As String, ByVal isFirst As Boolean)
End Sub
Public Sub AddStyleSheet(ByVal id As String, ByVal href As String)
End Sub

到此你应该知道我会如何开始注入样式, 具体的做法就是声明一个CDefault类型的只读属性, 比如本例为BasePage, 然后在需要注入样式时直接调用BasePage的AddStyleSheet方法, 当然缓存判断是必不可少的(类似代码应用可在这一文章也能找到加速DNN的新举措), 详细代码:
Imports System
Imports DotNetNuke.Framework
Imports DotNetNuke.Common.Globals
Imports DotNetNuke.Entities.Portals
Imports DotNetNuke.Entities.Modules
Namespace DnnUnion.Modules.SunBlog
Public Class BlogModuleBase
Inherits PortalModuleBase
'.....
Public Sub AddStyle(ByVal styleFile As String)
' initialize reference paths to load the cascading style sheets
Dim ID As String
Dim objCSSCache As Hashtable = CType(DataCache.GetCache("CSS"), Hashtable)
If objCSSCache Is Nothing Then
objCSSCache = New Hashtable
End If
ID = CreateValidID(ModulePath & styleFile).TrimStart(New Char() {"_"})
If objCSSCache.ContainsKey(ID) = False Then
objCSSCache(ID) = ModulePath & "Styles/" & styleFile & ".css"
'check whether cache disabled
If Not PerformanceSetting = PerformanceSettings.NoCaching Then
DataCache.SetCache("CSS", objCSSCache)
End If
End If
If objCSSCache(ID).ToString <> "" Then
BasePage.AddStyleSheet(ID, ModulePath & "Styles/" & styleFile & ".css")
End If
End Sub
Public ReadOnly Property BasePage() As CDefault
Get
Return CType(Me.Page, CDefault)
End Get
End Property
'...
End Class
End Namespace
Ok, 到此注入样式应该没有问题, 你在Page_Init或Page_Load事件调用AddStyle即可. :) Enjoy DNN
补充: 下一个帖子也许会谈谈如何动态压缩CSS, 因为如果页面复杂些则可能会存在很多样式文件(夸张时也是十几个样式文件), 如此一来http请求将增多, 则无疑将加剧服务器的负担, 如何更好的优化DNN网站需要你我的探索 :)