learn by ExtExtenders' src(1) 日历

什么是Ext Extender?
ExtExtenders是由 Rodrigo Diniz开发的一组对Extjs 客户端控件的.net服务器端包装控件
由Extender可知道其运行必须ASP.NET AJAX框架的支持.
类似的项目有Coolite,但为什么我们更应该关注ExtExtenders呢? 开源,而且功能更加强大.
演示地址 http://www.extendersamples.qsh.eu/
项目主页 http://www.codeplex.com/ExtJsExtenderControl
开源软件的最大好处就是我们不仅能够利用它来为我们的工作带来方便,而且能够透过其源代码,学习作者的实现方法,
领悟其设计思路,加快我们进步的步伐,正所谓是站在巨人的肩膀上,好风凭借力.

一如往常的技术介绍文章,让我们从最简单的开始,Extjs的日历组件界面美观,功能也非常强大而且没有复杂的服务器端 - 客户端交互行为, 就让我们先拿它开刀吧

首先我们到Codeplex下载一份源代码,这里以版本31017作为示例.
解压好后,先看到GridControl目录下的几个文件: YUI.cs, YUI-ext.cs, ext-yui-adapter.cs .
可以看到这几个文件实现非常简单:就是一个静态类,标注了其需要使用的嵌入式资源.
 1 [assembly: System.Web.UI.WebResource( " ExtExtenders.yui.js " " text/javascript " )]
 2 namespace  ExtExtenders
 3 {
 4    /**//// <summary>
 5    /// Class to include the js file
 6    /// </summary>  

 7    public static class YUI
 8    {
 9    }

10}

然后来到今天的主角Calendar,这个文件夹里分别有 CalendarExtenderExtender.cs 和一个脚本文件 CalendarExtenderBehavior.js(注意到整个项目里的js和css以及图片文件都设为了嵌入式文件)
看看 CalendarExtenderExtender.cs 里到底实现了啥
Code
  1[ToolboxBitmap(typeof(System.Web.UI.WebControls.Calendar))]
  2    public class ExtCalendar : TextBox, IScriptControl
  3    {
  4        private ScriptManager sm;
  5        private string _disabledDays;
  6        /**//// <summary>
  7        /// An array of days to disable, 0 based. For example, [0, 6] disables 
  8        /// Sunday and Saturday (defaults to null).
  9        /// </summary>

 10        public string disabledDays
 11        {
 12            get
 13            {
 14                return _disabledDays;
 15            }

 16            set
 17            {
 18                _disabledDays=value;
 19            }

 20        }

 21        private string _disabledDaysText;
 22        /**//// <summary>
 23        /// The message that appears when a date is disabled
 24        /// </summary>

 25        public string disabledDaysText
 26        {
 27            get
 28            {
 29                return _disabledDaysText;
 30            }

 31            set
 32            {
 33                _disabledDaysText=value;
 34            }

 35        }

 36        private string _disabledDates;
 37        /**//// <summary>
 38        /// An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so they are very powerful.
 39        /// Some examples:  * ["03/08/2003", "09/16/2003"] would disable those exact dates
 40       /// * ["03/08", "09/16"] would disable those days for every year
 41       ///* ["^03/08"] would only match the beginning (useful if you are using short years)
 42        ///* ["03/../2006"] would disable every day in March 2006
 43       ///* ["^03"] would disable every day in every March
 44       ///In order to support regular expressions, if you are using a date format that has "." in it, you will have to escape the dot when restricting dates. For example: ["03\\.08\\.03"].
 45        /// </summary>

 46        public string disabledDates
 47        {
 48            get
 49            {
 50                return _disabledDates;
 51            }

 52            set
 53            {
 54                _disabledDates=value;
 55            }

 56        }

 57        private string _disabledDatesText;
 58        /**//// <summary>
 59        ///  The tooltip text to display when the date falls on a
 60        /// disabled date (defaults to 'Disabled')
 61        /// </summary>

 62        public string disabledDatesText
 63        {
 64            get
 65            {
 66                return _disabledDatesText;
 67            }

 68            set
 69            {
 70                _disabledDatesText=value;
 71            }

 72        }

 73        private string _format;
 74        /**//// <summary>
 75        /// The default date format string which can be overriden for localization support. 
 76        /// The format must be valid according to Date.parseDate (defaults to 'm/d/y').
 77        /// </summary>

 78        public string format
 79        {
 80            get
 81            {
 82                return _format;
 83            }

 84            set
 85            {
 86              _format=value;
 87            }

 88        }

 89
 90        /**//// <summary>
 91        /// Raises the pre render event.
 92        /// </summary>
 93        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>

 94        protected override void OnPreRender(EventArgs e)
 95        {
 96            base.OnPreRender(e);
 97            string resource = Page.ClientScript.GetWebResourceUrl(GetType(), "ExtExtenders.yui-ext.css");
 98            string csslink = "<link href='" + resource + "' rel='stylesheet' type='text/css' />";
 99            Page.Header.Controls.Add(new LiteralControl(csslink));
100            ClientScriptManager man = Page.ClientScript;
101            //render the yui-ext scripts
102            man.RegisterClientScriptResource(typeof(YUI), "ExtExtenders.yui.js");
103            man.RegisterClientScriptResource(typeof(YUI_ext), "ExtExtenders.yui-ext.js");
104            man.RegisterClientScriptResource(typeof(ext_yui_adapter), "ExtExtenders.ext-yui-adapter.js");
105            if (!this.DesignMode)
106            {
107                // Test for ScriptManager and register if it exists
108                sm = ScriptManager.GetCurrent(Page);
109
110                if (sm == null)
111                    throw new HttpException("A ScriptManager control must exist on the current page.");
112
113                sm.RegisterScriptControl(this);
114            }

115           
116        }

117        /**//// <summary>
118        /// Renders the control to the specified HTML writer.
119        /// </summary>
120        /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"></see> object that receives the control content.</param>

121        protected override void Render(HtmlTextWriter writer)
122        {   
123            base.Render(writer);
124            if (!this.DesignMode)
125                sm.RegisterScriptDescriptors(this);
126         
127        }

128       
129        IScriptControl Members#region IScriptControl Members
130
131        /**//// <summary>
132        /// Gets the script descriptors.
133        /// </summary>
134        /// <returns></returns>

135        public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
136        {
137            ScriptControlDescriptor descriptor = new ScriptControlDescriptor(
138                                         "ExtExtenders.CalendarExtenderBehavior"this.ClientID);
139
140            Type t = this.GetType();
141            //properties that will be serialized
142            string[] propsToSerialize = {
143                "disabledDays","disabledDaysText","disabledDates",
144                "disabledDatesText","format"
145               }
;
146            foreach (string prop in propsToSerialize)
147            {
148                PropertyInfo p = t.GetProperty(prop);
149                if (p == null)
150                {
151                    throw new Exception(prop);
152                }

153                descriptor.AddProperty(p.Name, p.GetValue(thisnull));
154            }

155            return new ScriptDescriptor[] { descriptor };
156        }

157
158        /**//// <summary>
159        /// Gets the script references.
160        /// </summary>
161        /// <returns></returns>

162        public IEnumerable<ScriptReference> GetScriptReferences()
163        {
164            ScriptReference reference = new ScriptReference();
165            if (Page != null)
166                reference.Path = Page.ClientScript.GetWebResourceUrl(this.GetType(),
167                                  "ExtExtenders.calendar.CalendarExtenderBehavior.js");
168
169            return new ScriptReference[] { reference };
170        }

171
172        #endregion

173    }

由声明可知,ExtCalendar直接继承了TextBox,且实现了IScriptControl.
让我们来看看IScriptControl的接口规范, msdn之
1 public   interface  IScriptControl
2 {
3    IEnumerable<ScriptDescriptor> GetScriptDescriptors();
4    IEnumerable<ScriptReference> GetScriptReferences();
5}

当一个类实现了IScriptControl,其需要分别实现两个方法.
GetScriptDescriptors()方法用来返回客户端元素是如何与该服务器端控件进行数据交互的Descriptor
GetScriptReferences()方法则告诉ScriptManager在程序运行时需要引入哪些script以及路径.

其后,ExtCalendar声明了一系列对应于Extjs库中Calendar客户端组件的属性. 并且重写了TextBox的OnPreRender方法注册了所需要的客户端资源.
这里需要注意的是,如果我们要使用中文版的ExtCalender的话,需要从Extjs的资源包中拷贝ext-lang-zh_CN.js到项目中设为嵌入式资源并且修改YUI.cs
在类声明上添加[assembly: System.Web.UI.WebResource("ExtExtenders.ext-lang-zh_CN.js", "text/javascript")]

接下来,看看作者是如何实现IScriptControl接口的 .
GetScriptReferences()很简单, 返回路径为ExtExtenders.calendar.CalendarBehaviorExtender.js的ScriptReference对象实例.
GetScriptDescriptors()呢 ?
由代码可知.  作者先新建了一个ScriptControlDescriptor对象实例,
然后把ExtCalendar的各个对应Extjs的客户端Calendar组件的属性添加上述的descriptror中,在控件的Render()事件中利用控件所处页面的ScriptManager注册这个descriptor,达到与客户端元素交互的目的.

来到客户端的实现

CalendarExtenderBehavior.js
 1
 2Type.registerNamespace('ExtExtenders');
 3ExtExtenders.CalendarExtenderBehavior = function(element) {
 4   
 5    ExtExtenders.CalendarExtenderBehavior.initializeBase(this, [element]);
 6      
 7}

 8ExtExtenders.CalendarExtenderBehavior.prototype = {
 9    initialize: function() {
10    
11        ExtExtenders.CalendarExtenderBehavior.callBaseMethod(this'initialize');
12        var id=this.get_element().id;
13        var objConfig={};
14        objConfig.fieldClass=document.getElementById(id).className;
15        objConfig.focusClass=document.getElementById(id).className;
16        if(this._disabledDaysText!=null){
17            objConfig.disabledDaysText=this._disabledDaysText;
18        }

19        if(this._disabledDays !=null){
20            objConfig.disabledDays= eval(this._disabledDays);
21        }

22        if(this._disabledDates!=""){
23            objConfig.disabledDates=eval(this._disabledDates);
24        }

25        if(this._disabledDatesText!=""){
26            objConfig.disabledDatesText=this._disabledDatesText;
27        }

28        objConfig.applyTo=id;
29        var dtField= new Ext.form.DateField(objConfig);
30        if(this._format!=""){
31            dtField.format=this._format;
32        }

33       
34        dtField.render();
35       
36    }
,
37    
38    get_disabledDates: function() {
39       
40        return this._disabledDates;
41    }
,
42    set_disabledDates: function(value) {
43        this._disabledDates = value;
44    }
,
45    
46    get_disabledDatesText: function() {
47     
48        return this._disabledDatesText;
49    }
,
50    set_disabledDatesText: function(value) {
51        this._disabledDatesText = value;
52    }
,
53    get_format: function() {
54     
55        return this._format;
56    }
,
57    set_format :function(value) {
58        this._format = value;
59    }
,
60    get_disabledDays:function(){
61       return this._disabledDays;
62    }
,
63    set_disabledDays:function(value){
64        this._disabledDays=value;
65    }
,
66    get_disabledDaysText:function(){
67        return this._disabledDaysText;
68    }
,
69    set_disabledDaysText:function(value){
70        this._disabledDaysText=value;
71    }

72    
73}

74ExtExtenders.CalendarExtenderBehavior.registerClass('ExtExtenders.CalendarExtenderBehavior', Sys.UI.Control);

脚本代码的第2,3行分明声明了一个名为ExtExtenders的命名空间以及该命名空间下的CalendarExtenderBehavior类. 在其后的原型声明中,initialize方法构造了一个客户端的Ext.form.DateField对象并且在页面呈现.
注意到js文件里有一系列get_XX, set_XX方法  它的作用就是按照get(set)_PropertyName的格式来传递服务器端ScriptDescriptor对象所具有的Property值.
最后一行, 作者把CalendarExtenderBehavior作为Sys.UI.Control的子类注册.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
在下一节中,我们将继续更为复杂的控件,并且尝试着改良作者的设计.



转载于:https://www.cnblogs.com/yyliuliang/archive/2008/05/30/1210771.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值