在实际的项目中,存在这么一个问题:所有页面都从自定义的页面基类(MyPageBase)中继承过来。一些公共的方法可以在基类中实现。其中有一个是防止并发问题的,任何页面在绑定数据之前,都去检查是否有其它用户以可写的方式打开了此文档(写独占),如果被他人独占,则以只读方式打开。同时在页面中显示如“只读”标识,这样既很好地避免了并发的问题,同时又很清楚的告诉当前用户“你现在只能浏览本文档,因为他人正在修改此文档……”(如图1)。现在问题来了:我不可能要求其它程序员都在自己做的页面的某个位置手工放置“只读”标识吧?!这样做重复劳动不说,风格也很难统一。怎么办呢?
如果在WinForm中,基类Form可以拖个Label控件,label1.Text = “只读”(或者是一副图片),则其所有派生类都会有这个Label控件。但WebForm中就不行,因为在Web中页面(指WebForm1.aspx)之间不能像WinForm一样实现继承,但页面的代码类(指WebForm1.aspx.cs)可以继承。分析Web程序的原理:服务器接受客户端的请求后,经过处理生成一个Html的文本发送给客户端,如果我们可以在服务器发送Html的文本到客户端之前对Html的文本进行修改,然后再发送给客户端,那问题就能得到解决。幸运的是:页面类Page中有一个Render(HtmlTextWriter writer)方法可以承载。
做法:我在页面基类(MyPageBase)承载Render(HtmlTextWriter writer)方法,然后在得到的Html的文本中的<body>标识与<form>之间插入一段标识文本,用来标识文档是否“只读”。这样,所有从此页面基类中派生过来的页面,都在最顶端标出文档是否“只读”。当然是否显示“只读”标识必须看是否只读打开此文档的,如果不是只读打开(没有他人独占文档),则没必要显示“只读”标识,如图2。
图2
代码如下:
1/// <summary>
2 /// 本项目中所有页面的基类
3 /// </summary>
4 public class MyPageBase : System.Web.UI.Page
5 {
6
7 private bool _isReadOnly = true;
8
9 protected override void Page_Load(object sender, EventArgs e)
10 {
11 base.Page_Load(sender, e);
12
13
14 if (!IsPostBack)
15 {
16 try
17 {
18 this.MainDataSet = this.ManagerProvider.Open(DocID, false); //DocID为文档的ID
19 this.ViewState.Add("IsReadOnly",false);
20 }
21 catch(LockException lockEx) //LockException为自定义的锁定异常类
22 {
23 this.MainDataSet = this.ManagerProvider.Open(DocID, true);
24 this.ViewState.Add("IsReadOnly",true);
25
26 SetPageReadOnly(); //设置页面为只读的
27 }
28
30
31 }
32
33 }
34
35
36 /// <summary>
37 /// 根据本页面/文档是是否是“只读”,选择是否加载“只读”图片
38 /// </summary>
39 protected override void Render(HtmlTextWriter writer)
40 {
41 bool isReadOnly = (bool)this.ViewState["IsReadOnly"];
42 if(isReadOnly )
43 {
44 StringWriter wt = new StringWriter();
45 HtmlTextWriter buffer = new HtmlTextWriter(wt);
46 base.Render(buffer);
47
48 string pMarkup = wt.ToString();
49 int indexEndBody = 0;
50 string readonlyFlag = @"<table width=100% border=0 cellspacing=0 cellpadding=0>
51 <tr>
52 <td><img src=../../include/images/ReadOnly.JPG width=404 height=58 align=left></td>
53 </tr>
54 </table>";
55
56 indexEndBody = pMarkup.IndexOf(">",pMarkup.IndexOf("<body"));
57 pMarkup = pMarkup.Insert(indexEndBody + 1, readonlyFlag);
58
59 writer.Write(pMarkup);
60 }
61 else
62 base.Render(writer);
63 }
64
65
66 /// <summary>
67 /// 设置页面为只读的,派生类可以重载此方法,加入对页面中各控件的Enable属性的设置。
68 /// </summary>
69 protected virtual void SetPageReadOnly()
70 {
71 }
72
2 /// 本项目中所有页面的基类
3 /// </summary>
4 public class MyPageBase : System.Web.UI.Page
5 {
6
7 private bool _isReadOnly = true;
8
9 protected override void Page_Load(object sender, EventArgs e)
10 {
11 base.Page_Load(sender, e);
12
13
14 if (!IsPostBack)
15 {
16 try
17 {
18 this.MainDataSet = this.ManagerProvider.Open(DocID, false); //DocID为文档的ID
19 this.ViewState.Add("IsReadOnly",false);
20 }
21 catch(LockException lockEx) //LockException为自定义的锁定异常类
22 {
23 this.MainDataSet = this.ManagerProvider.Open(DocID, true);
24 this.ViewState.Add("IsReadOnly",true);
25
26 SetPageReadOnly(); //设置页面为只读的
27 }
28
30
31 }
32
33 }
34
35
36 /// <summary>
37 /// 根据本页面/文档是是否是“只读”,选择是否加载“只读”图片
38 /// </summary>
39 protected override void Render(HtmlTextWriter writer)
40 {
41 bool isReadOnly = (bool)this.ViewState["IsReadOnly"];
42 if(isReadOnly )
43 {
44 StringWriter wt = new StringWriter();
45 HtmlTextWriter buffer = new HtmlTextWriter(wt);
46 base.Render(buffer);
47
48 string pMarkup = wt.ToString();
49 int indexEndBody = 0;
50 string readonlyFlag = @"<table width=100% border=0 cellspacing=0 cellpadding=0>
51 <tr>
52 <td><img src=../../include/images/ReadOnly.JPG width=404 height=58 align=left></td>
53 </tr>
54 </table>";
55
56 indexEndBody = pMarkup.IndexOf(">",pMarkup.IndexOf("<body"));
57 pMarkup = pMarkup.Insert(indexEndBody + 1, readonlyFlag);
58
59 writer.Write(pMarkup);
60 }
61 else
62 base.Render(writer);
63 }
64
65
66 /// <summary>
67 /// 设置页面为只读的,派生类可以重载此方法,加入对页面中各控件的Enable属性的设置。
68 /// </summary>
69 protected virtual void SetPageReadOnly()
70 {
71 }
72
Arbean Wu 于广州
2005-6-7