还记得duwamish吗?在那里面,一些页面由用户控件组成,而其所承担的逻辑处理都是在控件内部完成的,这样是把控件做为单独的逻辑模块使用。在forum里,我们又看到了这种处理方法,并且,更加的复杂和灵活,用来实现皮肤主题的更换。
通过前面的两篇笔记,已经大致了解了forum的控件使用,下面就做一次该方面的总结。(广告时间:之所以先关注这个,是因为我想把下一版的stella里使用这种模式。请大家期待大概两个星期后完成的Stella Forum V 1.2)
在forum中,页面由“模块控件”(我自己起的名字,呵呵)组成,这些模块控件其实是由负责呈现内容的的用户控件和负责进行逻辑处理的自定义空间共同组成的。这样的隔离处理是为了可以方便的更换用户控件达到更换皮肤的目的,逻辑操作都一样,所以后面的自定义控件就不需要改动。还有比较重要的是,页面上标记的都是自定义控件,这个也不会因皮肤的更换而修改。
实际上,forum里的页面和用户控件很少有codebehind的代码,因为逻辑即处理都交给自定义控件了。这样可以达到一种即插即用的效果,比如那个登陆模块,你可以随心的放到任何地方,而不用修改页面处理代码。
主题文件都放在统一的目录下,加载的时候会直接到该目录下找相应的文件。
拿登陆控件来分析,主要设计这三个控件:
Skin-Login.ascx
AspNetForums.Controls.Login
AspNetForums.Controls.SkinnedForumWebControl
Skin-Login提供了登陆时需要呈现的html,包括文本框、按钮等,Login用来初始化Login并对提交事件进行处理,SkinnedForumWebControl是Login的基类,主要作用是动态加载需要使用的用户控件。
CreateChildControls方法扮演了重要的角色,SkinnedForumWebControl里有两个方法LoadSkin和 InitializeSkin都是在CreateChildControls被使用。详细的说,先是LoadSkin加载要使用的用户控件,然后在 InitializeSkin里对这个控件进行初始化。注意InitializeSkin是vietual的,这个方法的实现主要是在个各子类(也就是具 体的自定义控件,在这里是Login)。在InitializeSkin重要的是对各种事件的订阅,比如登陆时要点按钮,对点击事件的订阅就在这里。过程 就是先用FindControl找到相应的控件,然后在处理。
要加载的具体控件是在子类中先定好,然后在基类中加载。CreateChildControls的触发顺序是先子类后基类。
系统怎么知道该加载哪个主题?这个一开始有个默认设置,然后用户可以自己更改需要的主题。在用户控制面板中可以看到该选项。
接下来的问题,在用户面板中可以选择需要哪个主题,那系统是怎么知道都有哪些主题?我们可以看提供选择的那个控件是AspNetForums.Controls.ThemeDropDownList,在该控件里完成了该项功能,在这里给出一行代码:
string[] dirs = Directory.GetDirectories( context.Request.PhysicalApplicationPath + ForumConfiguration.GetConfig().ForumFilesPath + "\\themes" );
这样,forum是直接到themes文件夹下看有哪些主题包,然后显示出来供选择。大家可以到官网http://bbs.hidotnet.com/ 下一个主题包,然后直接解压到这个文件夹,这样新的主题就可以用了。刚才我下了那个龙翔的主题,也没有看安装说明什么的,直接就把里面的default文 件夹改名成lxSkin,然后放到themes里,就直接可以用了,用户在选择的时候会看到两个选择default和lxSkin。换肤的大至流程如下:
以Skin-DisplayUserWelcome.ascx为例(这个是是否登陆状态显示)
1、View-ForumGroupView.ascx文件引入AspNetForums.Controls别名为Forums
2、在希望出现“是否登陆状态”显示的地方使用<Forums
AspNetForums.Controls.DisplayUserWelcome
3、在DisplayUserWelcome类中要做
A、设定皮肤的名称skinFilename
B、重写InitializeSkin(Control skin)函数,用于实现皮肤上的控件
C、如果与SkinnedForumWebControl类的CreateChildControls()进行的操作有所区别,还需要
重写CreateChildControls(),不过可以只写出区别部分,然后用base调用。
D、如果控件存在事件,还需要编写事件
4、在皮肤中需要设定控件显示的布局,控件名称应该与DisplayUserWelcome类中实现的控件名称相同
在换肤过程中SkinnedForumWebControl类是至关重要的一个类,他通过实现INamingContainer接口来区分
控件,通过重写CreateChildControls()来复合控件。
注明:CreateChildControls()在默认情况下会被OnPreRender()调用,也会在FindControl()调用
OnPreRender()/*会在页面呈现时之前会调用*/
FindControl()/*查找某一控件*/
目前我在AspNetForums只发现了三种类别的皮肤,
1、MasterPage.ascx为代表的总框架皮肤
2、View-ForumGroupView.ascx为代表的皮肤容器
3、Skin-DisplayUserWelcome.ascx为代表的功能皮肤
那么如果你想改变一页面中某一个块的位置,那么你应该去修改皮肤容器,如果要改变的是某一块内部的布局则需要修改功能皮肤
在default.aspx中大约用到了如下几个用户控件
delfault.aspx
View-ForumGroupView.ascx//首页的整体布区
Skin-LoginSmall.ascx//登陆那一块
Skin-NavigationMenu.ascx//菜单
Skin-Banner.ascx
Skin-DisplayUserWelcome.ascx//状态
Skin-DisplayTitle.ascx//声明
Skin-Statistics.ascx//统计信息
Skin-WhoIsOnline.ascx//在线信息
Skin-DisplayLegendForum.ascx//论坛图例
MasterPage.ascx