家园博客设计之一:模板加载
今天周末,休息一下,一觉就睡到了12点,嘎嘎。这个学期还是第一回,自从开学以来,看了半个月的书,接下了大多在修改家园的博客。前几天完工了 ,现在把写在家园的一篇博客copy过来。
一套博客系统最重要的部分就要属模板了,对于风格每个人都有自己不同需求,系统需要适应各种模板和将来的扩展性。对于家园来说完全自己设计模板不太可能的,不管是技术上还是时间精力都是不允许的。
模板构架有好多种:
1.HTML不变而只是更css样式。这种模板的可用性非常低,一旦后期网站改版以前所有的模板可能都无法使用了,就像校内(部分原因吧)。现有的博客系统大多使用这种。
2.只是跟换html页面。这样灵活得很,技术工作量太大,就像博客园就用的这种。
3.还有就是更改部分的html
4.当然网站有段时间提倡一种使用xml 和xslt分离的格式设计。这种做法模板和代码彻底的分离,很好做。只是这种对搜索优化不太好,而且开发的成本太高,不好调试,html还要转成xslt。不过这样做出来的网站性能肯定好,字符操作都扔给了browser。 x3bog就是这种做法。
家园博客采用的是html跟换的模式,同时每套html有多套不同css。这样找到了很好的平衡,扩展起来也非常简单。所有的模板都是网上开源的博客系统提取出来或者自己写小程序从目标博客网站批量下载下来的。
之前的博客都是2008做好的,那是没有现在普及宽屏,因此对宽屏可能支持不是很好,模板还要添加以写(现在是5套)。
下面是具体的技术细节:
Asp.net 的page就是一个control树的容器,page的初始化就是构架control树,经历各种处理之后Render出一个html串。
它允许我们动态加载一个usercontrol,其实质就是反射一个control类。
第一步:我们需要把页面分成两个部分,head 和body;分成两个部分加载,因为一个page 有且只有一个head,一个form runat server。
1<%@ Page Language="C#" Inherits="Ncuhome.Blog.Core.DefaultPageBase" AutoEventWireup="true"
2 EnableViewState="false" %>
3
4<head id="Head1" runat="server">
5 <Blog:Index_Head runat="server" ID="Index_Head1" />
6</head>
7<body>
8 <form runat="server" id="form1">
9 <Blog:Index_Form runat="server" ID="Index_Form1" />
10 <span style="display:none"><embed src="<%= Ncuhome.Blog.Core.BlogContext.Current.Owner.User_BackGroundMusic %>" autostart="true"></span>
11 </form>
12</body>
13</html>
2 EnableViewState="false" %>
3
4<head id="Head1" runat="server">
5 <Blog:Index_Head runat="server" ID="Index_Head1" />
6</head>
7<body>
8 <form runat="server" id="form1">
9 <Blog:Index_Form runat="server" ID="Index_Form1" />
10 <span style="display:none"><embed src="<%= Ncuhome.Blog.Core.BlogContext.Current.Owner.User_BackGroundMusic %>" autostart="true"></span>
11 </form>
12</body>
13</html>
根据不同参数更改加载不同的ascx。
下面是我们控件基类:
1using System;
2using System.ComponentModel;
3using Ncuhome.Blog.Core;
4using System.IO;
5using System.Web.UI;
6
7namespace Ncuhome.Blog.Controls
8{
9 [ParseChildren(true)]
10 /// <summary>
11 /// 皮肤控件基类
12 /// </summary>
13 public abstract class SkinnedBlogWebControl : Control, INamingContainer
14 {
15 //构造
16 public SkinnedBlogWebControl()
17 {
18 }
19 //字段
20 public string SkinFilename { get; set; }
21 public bool IsThemed { get; set; }
22 public BlogContext blogContext =BlogContext.Current;
23 //创建子控件
24 protected override void CreateChildControls()
25 {
26 Control Skin = null;
27 Skin = LoadSkin();
28 InitializeSkin(Skin);
29 Controls.Add(Skin);
30 }
31 /// <summary>
32 /// 加载皮肤
33 /// </summary>
34 /// <returns></returns>
35 protected Control LoadSkin()
36 {
37 Control Skin;
38 string SkinPath=string.Empty;
39 if (IsThemed)
40 {
41 if (!string.IsNullOrEmpty(Ncuhome.Blog.Core.BlogContext.Current.ThemeName))
42 SkinPath = "\Themes\" + Ncuhome.Blog.Core.BlogContext.Current.ThemeName.Trim() + "\" + SkinFilename.TrimStart('\');
43 else
44 Globals.ErrorPageTransfer("对不起,该页不存在!");
45 }
46 else
47 SkinPath = "\Themes\NoTheme\" + SkinFilename.TrimStart('\');
48 if (SkinFilename == null)
49 throw new Exception("你必须指定皮肤的文件名");
50 try
51 {
52 Skin = Page.LoadControl(SkinPath);
53 }
54 catch (FileNotFoundException)
55 {
56 throw new Exception("错误:皮肤文件 " + SkinPath + " 没有找到. 皮肤必须被指定,以用于控件的呈现.");
57 }
58 return Skin;
59 }
60 /// <summary>
61 ///皮肤初始化,一个抽象的方法,control继承此类的时候实现这个方法。用于绑定加载控件的添加数据 (抽像类)
62 /// </summary>
63 protected abstract void InitializeSkin(Control Skin);
64 }
65}
66
2using System.ComponentModel;
3using Ncuhome.Blog.Core;
4using System.IO;
5using System.Web.UI;
6
7namespace Ncuhome.Blog.Controls
8{
9 [ParseChildren(true)]
10 /// <summary>
11 /// 皮肤控件基类
12 /// </summary>
13 public abstract class SkinnedBlogWebControl : Control, INamingContainer
14 {
15 //构造
16 public SkinnedBlogWebControl()
17 {
18 }
19 //字段
20 public string SkinFilename { get; set; }
21 public bool IsThemed { get; set; }
22 public BlogContext blogContext =BlogContext.Current;
23 //创建子控件
24 protected override void CreateChildControls()
25 {
26 Control Skin = null;
27 Skin = LoadSkin();
28 InitializeSkin(Skin);
29 Controls.Add(Skin);
30 }
31 /// <summary>
32 /// 加载皮肤
33 /// </summary>
34 /// <returns></returns>
35 protected Control LoadSkin()
36 {
37 Control Skin;
38 string SkinPath=string.Empty;
39 if (IsThemed)
40 {
41 if (!string.IsNullOrEmpty(Ncuhome.Blog.Core.BlogContext.Current.ThemeName))
42 SkinPath = "\Themes\" + Ncuhome.Blog.Core.BlogContext.Current.ThemeName.Trim() + "\" + SkinFilename.TrimStart('\');
43 else
44 Globals.ErrorPageTransfer("对不起,该页不存在!");
45 }
46 else
47 SkinPath = "\Themes\NoTheme\" + SkinFilename.TrimStart('\');
48 if (SkinFilename == null)
49 throw new Exception("你必须指定皮肤的文件名");
50 try
51 {
52 Skin = Page.LoadControl(SkinPath);
53 }
54 catch (FileNotFoundException)
55 {
56 throw new Exception("错误:皮肤文件 " + SkinPath + " 没有找到. 皮肤必须被指定,以用于控件的呈现.");
57 }
58 return Skin;
59 }
60 /// <summary>
61 ///皮肤初始化,一个抽象的方法,control继承此类的时候实现这个方法。用于绑定加载控件的添加数据 (抽像类)
62 /// </summary>
63 protected abstract void InitializeSkin(Control Skin);
64 }
65}
66
可以看到这个事一个抽象类,首先他重写了:继承control类的CreateChildControls()方法,该方法会在page初始化的时候被调用,我们在里面
1 Control Skin = null;
2 Skin = LoadSkin();
3 InitializeSkin(Skin);
4 Controls.Add(Skin);
2 Skin = LoadSkin();
3 InitializeSkin(Skin);
4 Controls.Add(Skin);
这几句就是把控件初始化添加:使用 Skin = Page.LoadControl(SkinPath); 这个方法加载页面。
同时还有一个InitializeSkin()的抽象方法,c#里面要求继承一个抽象类需要实现它的抽象方法。
那就随意看一下我们的一个实现控件:
1using System;
2using System.Collections.Generic;
3using System.Web.UI.WebControls;
4using System.Text;
5using Ncuhome.Blog.Entity;
6using Ncuhome.Blog.Core;
7using System.Linq;
8
9namespace Ncuhome.Blog.Controls
10{
11 public class Comments :SkinnedBlogWebControl
12 {
13 private Repeater repeater1;
14 public Comments()
15 {
16 IsThemed = true;
17 SkinFilename = "Comments.ascx";
18 }
19 protected override void InitializeSkin(System.Web.UI.Control Skin)
20 {
21 repeater1 = (Repeater)(Skin.FindControl("repeater1"));
22 DataBind();
23 }
24 public override void DataBind()
25 {
26 repeater1.DataSource = BlogCache.GetUserCommentsListByLogID(blogContext.LogId);
27 repeater1.DataBind();
28 base.DataBind();
29 }
30 }
31}
32
2using System.Collections.Generic;
3using System.Web.UI.WebControls;
4using System.Text;
5using Ncuhome.Blog.Entity;
6using Ncuhome.Blog.Core;
7using System.Linq;
8
9namespace Ncuhome.Blog.Controls
10{
11 public class Comments :SkinnedBlogWebControl
12 {
13 private Repeater repeater1;
14 public Comments()
15 {
16 IsThemed = true;
17 SkinFilename = "Comments.ascx";
18 }
19 protected override void InitializeSkin(System.Web.UI.Control Skin)
20 {
21 repeater1 = (Repeater)(Skin.FindControl("repeater1"));
22 DataBind();
23 }
24 public override void DataBind()
25 {
26 repeater1.DataSource = BlogCache.GetUserCommentsListByLogID(blogContext.LogId);
27 repeater1.DataBind();
28 base.DataBind();
29 }
30 }
31}
32
这个是评论列表的control,initializeSkin的时候对立面的repeater控件做数据绑定的操作。
未完待续...