您的位置:首页 > 编程语言 > ASP

ASP.NET AJAX(13)__利用Microsoft AJAX Library开发客户端组件

2011-10-24 20:23 801 查看
MicrosoftAJAXLibrary定义了一个客户端组件的模型,它的基类是Sys.Component,它实现了三个接口Sys.IDisposable,Sys.INotifyDisposing,Sys.INotifyPropertyChange

Sys.Component成员

get_events()

get_id();

set_id();

get_isInitialized();

initialize();

dispose();

raisePropertyChanged();

Sys.IDisposable成员

dispose();

Sys.INotifyDisposing成员

add_disposing();

remove_disposing();

Sys.INotifyPropertyChange成员

add_propertyChanged();

remove_propertyChanged();

可视组件和不可视组件

可视组件,就是对DOM进行了封装,在MicrosoftAJAXLibrary中可分为两种Sys.UI.Control和Sys.UI.Behavior,不可视组件不继承于Control和Behavior,它是一种辅助对象

Control和Behavior

Sys.UI.Control:封装了DOM元素,概念上为一个组合的控件

Sys.UI.Behavior:扩展了DOM元素,为DOM元素提供了额外的功能

全局容器

Sys._Application为一个全局的容器类

维护着全局的所有Component对象的生命周期

客户端生命周期





这里的声明周期,很像我们的c#语言,实际上,它就是按照这种高级语言的声明周期来开发的,如果我们要创建对象,需要在Sys.Application.init事件中创建,并且调用Component的initialize方法,这样在load事件中,就可以在代码中控制它,这以为着,在Sys.Application的load阶段,所有的组件已经必须准备好

一个客户端与组件生命周期的示例
首先创建一个名为SimpleComponent.js的文件

///<referenctname="MicrosoftAjax.js"/>

Type.registerNamespace("Demo");//注册一个命名空间

Demo.SimpleComponent=function(){
Demo.SimpleComponent.initializeBase(this);//调用父类的构造函数
}

Demo.SimpleComponent.prototype=//添加成员
{
initialize:function(){
Demo.SimpleComponent.callBaseMethod(this,"initialize");//调用父类名为initialize的方法
alert("I'vebeeninitialized!");
},
dispose:function(){
alert("I'mbeingdisposed!");
Demo.SimpleComponent.callBaseMethod(this,"dispose");
},
sayHi:function(){
alert("Hello,i'myoufirstcomponent!");
}
}

Demo.SimpleComponent.registerClass("Demo.SimpleComponent",Sys.Component);//注册这个类,继承自Sys.Component

然后创建一个aspx页面

<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="SimpleLifeCycle.aspx.cs"Inherits="Demo12_SimpleLifeCycle"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title></title>
</head>
<body>
<formid="form1"runat="server">
<asp:ScriptManagerID="ScriptManager1"runat="server">
<Scripts>
<asp:ScriptReferencePath="~/Demo12/SimpleComponent.js"/>
</Scripts>
</asp:ScriptManager>

<scriptlanguage="javascript"type="text/javascript">
functionpageInit(){
alert("Pageisinitializaing!");
$create(//MicrosoftAJAXLibrary提供的创建对象的简单方法
Demo.SimpleComponent,//第一个参数,构造组件的类型
{"id":"simpleComponent"},//第二个参数,设置属性,这里只设置一个id
{"disposing":onDisposing});//第三个参数,设置事件
}

functionpageLoad(){//页面加载完成后被调用
varsimple=$find("simpleComponent");//找到simpleComponent这个组件
simple.sayHi();//调用组件的sayHi方法
}

functiononDisposing(){//Component释放的时候被调用
alert("Componentisbeingdisposed");
}

Sys.Application.add_init(pageInit);//把pageInit方法添加到Sys.Application的init事件中,这样在Sys.Application的init事件中方法被调用
</script>
</form>
</body>
</html>


我们打开这个页面,一步一步的观察调用步骤

1.Sys.Application.init事件被触发





2.Component的initialize被调用





3.pageLoad被调用Component的sayHi方法被执行





4.离开页面,组件的dispose方法被调用





5.我们已经在创建对象的时候响应了对象的disposing事件,onDisposing方法被执行





开发一个Component

Sys.Component类(非必须)

在构造函数里定义私有变量(将变量设置为默认值)

覆盖initialize方法,初始化所有私有变量

覆盖dispose方法,释放所有私有变量,避免资源泄漏

定义其他成员

一个简单的Component的示例
创建一个名为Timer.js的文件

Type.registerNamespace("Demo");

Demo.Timer=function(){
Demo.Timer.initializeBase(this);//调用基类构造函数
this._interval=1000;//私有变量设置为默认值
this._timer=null;//私有变量设置为默认值
}

Demo.Timer.prototype=
{
get_interval:function(){
returnthis._interval;
},
set_interval:function(value){
if(this._interval!=value){//判断现在已有interval的值,是否等于要设置的值
this._interval=value;
this.raisePropertyChanged("interval");//告诉外接interval属性被改变
if(this._timer){
this.stop();
this.start();
}
}
},
add_tick:function(handler){
this.get_events().addHandler("tick",handler);//添加一个事件tick为事件名
},
remove_tick:function(handler){
this.get_events().removeHandler("tick",handler);//去除一个事件tick为事件名
},
_timerCallback:function(){
varhandler=this.get_events().getHandler("tick");//得到我们设置的事件
if(handler){//如果这个事件存在
handler(this,Sys.EventArgs.Empty);
}
},
start:function(){
if(this._interval>0){
this._timer=window.setInterval(//这里使用的是javascript的原生方法
Function.createDelegate(this,this._timerCallback),//使_timerCallback的指针指向组件本身,而不是window
this._interval);
}
},
stop:function(){
if(this._timer){//如果_timer已经被赋值,证明已经开始啦
window.clearInterval(this._timer);
this._timer=null;
}
}
}

Demo.Timer.registerClass("Demo.Timer",Sys.Component);


创建一个aspx页面

<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="Timer.aspx.cs"Inherits="Demo12_Timer"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title></title>
</head>
<body>
<formid="form1"runat="server">
<asp:ScriptManagerID="ScriptManager1"runat="server">
<Scripts>
<asp:ScriptReferencePath="~/Demo12/Timer.js"/>
</Scripts>
</asp:ScriptManager>

Interval:
<inputtype="text"value="1000"id="txtInterval"/>
<inputtype="button"value="Change"onclick="changeInterval()"/><br/>

<divid="display"></div>

<scriptlanguage="javascript"type="text/javascript">
Sys.Application.add_init(function(){
$create(Demo.Timer,//创建这个Component
{"id":"timer"},//定义一个ID
{"tick":onTick,"propertyChanged":onPropertyChanged});//创建事件处理程序
});

functiononPropertyChanged(sender,args){//propertyChanged被触发的时候,此方法被调用
varproperty=args.get_propertyName();//得到改变属性的名称
varvalue=sender["get_"+property].apply(sender);//apply指定指针指向组件对象
alert(property+"ischangedto"+value);
}

window.counter=0;//一个计数器

functiononTick(){//组件的tick事件被触发时,此方法被调用
$get("display").innerHTML=window.counter++;
}

functionpageLoad(){//页面加载完成,timer开始工作
$find("timer").start();
}

functionchangeInterval(){
$find("timer").set_interval(
parseInt($get("txtInterval").value,10));
}
</script>
</form>
</body>
</html>


这里就使用到了我们创建的Component,实现一个计数器的效果,类似一个客户端的Timer

Sys.Component成员

events只读属性//事件集合

id属性//组件的id

initialize方法

isInitialized只读属性//是否在构造中

raisePropertyChanged方法//告诉外界哪个属性改变

propertyChanged事件//属性改变后触发

dispose方法

disposing事件

beginUpdate方法//开始Update

isUpdating只读属性//是否处于Update状态

endUpdate方法

updated方法

组件处于正在更新的状态称为Update状态,处于更新状态时候组件的数据可能出于不一致的状态,因此,出于更新状态的组件,允许组件处于不一直的状态,但是应该尽量避免与外接的交换,尤其是处于DOM元素有关的交互,有时候,合理的利用Update状态也能够在一定程序上提高性能

Update状态的使用

Sys.Component._setProperties方法:批量修改组件的属性(在非Update状态下)(调用beginUpdate方法->设置组件属性->调用endUpdate方法)

Update状态在系统中的使用

windows的DOM事件load被触发

Sys.Application对象的beginCreatComponent方法被调用

SysApplication对象的Init事件被触发

$Creat方法被调用,用于创建对象

组件的beginUpdate方法被调用

部分组件的endUpdate方法被调用

如果他们还没有被初始化,而initialize方法被调用

他们的Updated方法被调用

Sys.Application对象的endCreatComponent方法被调用

剩余组件的endUpdate方法被调用

开发时Update状态的使用方式

调用beginUpdate方法

修改属性

调用endUpdate方法,此外,经常重写Updated方法,提交组件更新信息

一个改进版的Timer示例
创建一个名为BetterTimer.js的文件

///<referencename="MicrosoftAjax.js"/>
Type.registerNamespace("Demo");

Demo.Timer=function(){
Demo.Timer.initializeBase(this);
this._interval=1000;
this._enabled=false;
this._timer=null;
}

Demo.Timer.prototype=
{
add_tick:function(handler){
this.get_events().addHandler("tick",handler);
},
remove_tick:function(handler){
this.get_events().removeHandler("tick",handler);
},
_timerCallback:function(){
varhandler=this.get_events().getHandler("tick");
if(handler){
handler(this,Sys.EventArgs.Empty);
}
},
_startTimer:function(){
this._timer=window.setInterval(
Function.createDelegate(this,this._timerCallback),
this._interval);
},
_stopTimer:function(){
window.clearInterval(this._timer);
this._timer=null;
},
get_interval:function(){
returnthis._interval;
},
set_interval:function(value){
if(this._interval!=value){
this._interval=value;
this.raisePropertyChanged("interval");
if(!this.get_isUpdating()&&this._timer!=null){//timer正在执行,而且组件不出于Update状态
this._stopTimer();
this._startTimer();
}
}
},
updated:function(){//重写父类的updated方法
Demo.Timer.callBaseMethod(this,"updated");//调用父类的updated方法
this._stopTimer();
if(this._enabled){
this._startTimer();
}
},
get_enabled:function(){
returnthis._enabled;
},
set_enabled:function(value){
if(value!=this._enabled){
this._enabled=value;
this.raisePropertyChanged("enabled");

if(!this.get_isUpdating()){//不出于更新状态
if(value){
this._startTimer();
}
else{
this._stopTimer();
}
}
}
},
dispose:function(){
this.set_enabled(false);
this._stopTimer();
Demo.Timer.callBaseMethod(this,"dispose");
}
}

Demo.Timer.registerClass("Demo.Timer",Sys.Component);


创建一个aspx的页面

<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="BetterTimer.aspx.cs"Inherits="Demo12_BetterTimer"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title></title>
</head>
<body>
<formid="form1"runat="server">
<asp:ScriptManagerID="ScriptManager1"runat="server">
<Scripts>
<asp:ScriptReferencePath="~/Demo12/BetterTimer.js"/>
</Scripts>
</asp:ScriptManager>

Interval:<inputtype="text"value="1000"id="txtInterval"/><br/>
<inputtype="checkbox"id="chkEnabled"checked="checked"/>
<labelfor="chkEnabled">Enabled</label><br/>
<inputtype="button"value="Change"onclick="changeStatus()"/>
<hr/>
<divid="display"></div>
<scriptlanguage="javascript"type="text/javascript">
Sys.Application.add_init(function(){
$create(Demo.Timer,
{"id":"timer","enabled":true},
{"tick":onTick});
});
window.counter=0;
functiononTick(){
$get("display").innerHTML=window.counter++;
}

functionchangeStatus(){
vartimer=$find("timer");
timer.beginUpdate();
timer.set_interval(parseInt($get("txtInterval").value,10));
timer.set_enabled($get("chkEnabled").checked);
timer.endUpdate();
}

</script>
</form>
</body>
</html>


Control模型(可视化组件模型)

封装一个DOM元素

提供统一的开发模型

可以用于开发复杂组件

构造函数接受一个element参数,表示这个组件封装的DOM元素

Sys.UI.Control类成员

element只读属性//要封装的元素

visibilityMode属性//枚举:hide(0)相当于style.visibility,collapse(1)相当于style.display

visable属性//bool,可见性

addCssClass方法//添加一个class样式

removeCssClass方法//去除一个class样式

toggleCssClass方法//如果没有一个class样式,而添加,如果有则去除

parent属性//

onBubbleEvent方法

raiseButtleEvent方法

一个使用Control模型的示例
创建一个名为TextBox.js的文件

///<referencename="MicrosoftAjax.js"/>

Type.registerNamespace("Demo");
Demo.TextBox=function(element){//注意这里有一个参数,是要封装的DOM元素
Demo.TextBox.initializeBase(this,[element]);
this._originalText=null;//保存元素中原先有的值
}

Demo.TextBox.prototype=
{
initialize:function(){
Demo.TextBox.callBaseMethod(this,"initialize");//调用父类方法
//响应文本框的change事件
$addHandler(this.get_element(),"change",
Function.createDelegate(this,this._onTextChange));
},
_onTextChange:function(e){
if(this.get_isUpdating()){
return;
}
varhandler=this.get_events().getHandler("textChange");
if(handler){
varargs=newSys.CancelEventArgs();
handler(this,args);

if(args.get_cancel()){
this.beginUpdate();//这样做,是为了设置文本框的text改变的时候,又会触发一个textChange事件
this.set_text(this._originalText);
this.endUpdate();
}
}
this._originalText=this.get_element().value;
},
add_textChange:function(handler){
this.get_events().addHandler("textChange",handler);
},
remove_textChange:function(handler){
this.get_events().removeHandler("textChange",handler);
},

//一个text属性
get_text:function(){
returnthis.get_element().value;//get_element方法,返回封装的DOM元素
},
set_text:function(value){
if(value!=null){
this.get_element().value=value;
}
else{
this.get_element().value="";
}
}
}

Demo.TextBox.registerClass("Demo.TextBox",Sys.UI.Control);


创建一个aspx页面

<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="TextBox.aspx.cs"Inherits="Demo12_TextBox"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title></title>
</head>
<body>
<formid="form1"runat="server">
<asp:ScriptManagerID="ScriptManager1"runat="server">
<Scripts>
<asp:ScriptReferencePath="~/Demo12/TextBox.js"/>
</Scripts>
</asp:ScriptManager>

<inputtype="text"id="textBox"/>

<scriptlanguage="javascript"type="text/javascript">
Sys.Application.add_init(function(){
$create(Demo.TextBox,//创建的组件类型
null,//这里不设置ID
{"textChange":onTextChange},//响应事件
null,
$get("textBox"));//需要封装的元素
});

functiononTextChange(sender,args){
varmessage=String.format("Thetextwouldbechangedto'{0}',areyousure?",sender.get_text());
if(!confirm(message)){
args.set_cancel(true);//确定“取消操作”
}
}
</script>
</form>
</body>
</html>


这样,我们实现了文本在改变以后,提示用户是不是确定操作,如果不确定这次操作,则可以撤销这次操作,注意,textChange是在改变文本后,焦点离开文本框以后触发的

我们使用这个组件,对一个普通的textbox进行的封装,这就是一个Control模型的使用示例

$creat方法

原型:$creat(type,properties,events,references,element);

referencts是一个字典,保存对象属性与其他对象的关系,key为属性名,value为其他对象id

保证initialize方法调用时,属性已经被设置为所需要的对象,几十调用$creat方法时,其他对象还没有创建

复合控件

复合控件主要会涉及到Control模型中的以下两个方法

raiseBubbleEvent(source,args);//由子控件调用,将触发的事件向父控件传递

onBubbleEvent(source,args);//父控件重写该方法,用于接受子控件向上传递过来的事件

这两个方法的主要作用是降低父控件和子控件之间的耦合关系,例如子控件不需要知道它的父控件是谁,只需要调用这个方法,把触发的事件向上传递就好啦,至于由谁来接受,这属于另外一个控件的设计啦

一个复合控件的示例
创建一个名为ButtonList.js的文件

///<referencename="MicrosoftAjax.js"/>

Type.registerNamespace("Demo");

Demo.Button=function(element){
Demo.Button.initializeBase(this,[element]);

this._context=null;//上下文对象,用于保存控件的一些信息
this._onClickHandler=null;//click事件的监听器
}

Demo.Button.prototype=
{
initialize:function(){
Demo.Button.callBaseMethod(this,"initialize");//调用基类方法
this._onClickHandler=Function.createDelegate(this,this._onClick);
$addHandler(this.get_element(),"click",this._onClickHandler);
},
//释放资源,防止资源泄漏
dispose:function(){
this._onClickHandler=null;
$clearHandlers(this.get_element());
Demo.Button.callBaseMethod(this,"dispose");
},
//元素点击后会调用
_onClick:function(e){
vareventArgs=newDemo.ButtonClickEventArgs(this._context);
this.raiseClick(eventArgs);
},

//context属性
get_context:function(){
returnthis._context;
},
set_context:function(value){
this._context=value;
},
//把事件向上传递
raiseClick:function(args){
this.raiseBubbleEvent(this,args);
}
}

Demo.Button.registerClass("Demo.Button",Sys.UI.Control);//注意,继承自Sys.UI.Control

//自定义的EventArgs
Demo.ButtonClickEventArgs=function(context){
Demo.ButtonClickEventArgs.initializeBase(this);
this._context=context;
}
Demo.ButtonClickEventArgs.prototype=
{
get_context:function(){
returnthis._context;
}
}

Demo.ButtonClickEventArgs.registerClass("Demo.ButtonClickEventArgs",Sys.EventArgs);//继承自Sys.EventArgs

Demo.ButtonList=function(element){
Demo.ButtonList.initializeBase(this,[element]);
this._itemDataList=null;//存储组件内包含的组件对象
}

Demo.ButtonList.prototype=
{
initialize:function(){
Demo.ButtonList.callBaseMethod(this,"initialize");
for(vari=0;i<this._itemDataList.length;i++){
this._createNewButton(this._itemDataList[i]);
}
},
_createNewButton:function(data){
varbuttonElement=document.createElement("input");//创建一个Input元素
buttonElement.type="button";//元素的type为button(按钮)
buttonElement.value=data.text;//按钮上的文字
this.get_element().appendChild(buttonElement);//按钮添加到这个组件上

//把创建的元素,用上面定义的组件进行封装
$create(Demo.Button,
{"context":data.context,"parent":this},//指定父控件为自身(ButtonList)
null,null,buttonElement);
},
get_itemDataList:function(){
returnthis._itemDataList;
},
set_itemDataList:function(value){
this._itemDataList=value;
},
//当有事件被传递上来的时候调用
onBubbleEvent:function(source,e){
this.raiseItemClick(e);
returntrue;//表示事件已经被处理掉了,不需要向上传递
},
add_itemClick:function(handler){
this.get_events().addHandler("itemClick",handler);
},
remove_itemClick:function(handler){
this.get_events().removeHandler("itemClick",handler);
},
raiseItemClick:function(args){
varhandler=this.get_events().getHandler("itemClick");
//如果有这个事件
if(handler){
handler(this,args);
}
}
}

Demo.ButtonList.registerClass("Demo.ButtonList",Sys.UI.Control);



然后,创建一个aspx页面

<%@PageLanguage="C#"AutoEventWireup="true"CodeFile="ButtonList.aspx.cs"Inherits="Demo12_ButtonList"%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title></title>
</head>
<body>
<formid="form1"runat="server">
<asp:ScriptManagerID="ScriptManager1"runat="server">
<Scripts>
<asp:ScriptReferencePath="~/Demo12/ButtonList.js"/>
</Scripts>
</asp:ScriptManager>

<divid="buttonList"></div>

<scriptlanguage="javascript"type="text/javascript">
Sys.Application.add_init(
function(){
vardatalist=
[
{
text:"Item1",
context:"Item1hasbeenclicked!"
},
{
text:"Item2",
context:"Item2hasbeenclicked!"
},
{
text:"Item3",
context:"Item3hasbeenclicked!"
}
];
$create(Demo.ButtonList,//组件类型
{"itemDataList":datalist},//指定属性
{"itemClick":onItemClick},//响应事件
null,
$get("buttonList"));//要封装的元素
}
);

functiononItemClick(sender,args){
alert(args.get_context());//得到args的context属性
}
</script>
</form>
</body>
</html>


运行页面,我们点击按钮就会看到弹出的结果,注意,这里的click事件虽然是子控件(Button)发起的,但是最后处理它的是我们创建的复合控件(ButtonList),这就是我们的raiseBubbleEvent方法和onBubbleEvent方法的功能和它们的使用方法

Behavior模型

另外一种可视化组件模型,继承与Sys.UI.Behavior

Control包装DOM元素,Behavior为DOM元素提供功能

一个DOM元素智能由一个Control来包装,但是可以使用多个Behavior进行装饰

Behavior成员

与Component组件相比唯一增加的属性是name

由于一个M元素上可以添加多个Behavior,因此如果要通过元素获得Behavior对象就需要通过name属性获得

$get("elementId")["name_of_behavior"]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐