PHP开发利器-PRADO 1.6(2)

- 中国WEB开发者网络 (http://www.webasp.net)
-- 技术教程 (http://www.webasp.net/article/)
--- PHP开发利器-PRADO 1.6(2) (http://www.webasp.net/article/28/27157.htm)
-- 作者:未知
-- 发布日期: 2005-12-23

静态创建组件

  通常只有控件在模板文件中被静态创建。

  一个控件在模板文件组件标签来声明,其语法如下: 

 ......
<com:ComponentType ID="..." PropertyName="..." EventName="...">
    ....body contents....
</com:ComponentType>
......

  这里  ComponentType, PropertyName, 和 EventName 应该被真正的组件类名,属性名和事件名所替代。 ID 属性是可选的。如果定义了ID 属性,那么ID 的值必须在平级的控件中是唯一的。如果没有定义,那么框架会自动为这个控件分配一个唯一的ID的。当然,这要求组件的标签被正确的嵌套,每一个开放的组件标签都应该和一个闭合的组件标签组成一对,这个规则和XML的规则是一样的。(译者著:如果你对XML一点都不了解,建议你先看一下一些基本的XML概念,要求并不高,你只需要知道如何正确书写一个XML文件即可。)

  注意:控件的ID必须是一个以字母开头的,后面只包含字母,数字和下划线的字符串。

  模板文件中属性的初始值字符串会被自动转换为正确的属性类型。目前有六种属性类型: string, integer, float, boolean, array  face="Courier New">和 object. 前面三种类型的字符串格式是非常简单的。 boolean 类型只允许使用两个字符串: true  face="Courier New">和 false。 array 类型接受如 (value1,value2,key3=>value3,...) 格式一样的字符串,这和 PHP 数组的初始化是一样的。 而 object 类型就比较复杂了,它取决于属性是如何被定义的。一些属性可以允许使用字符串,并会把它转换为对象,但是有些属性就不行了。

  当组件被创建(实例化)的时候,通过规格文件定义的组件的属性和对应事件处理方法就会立刻生效了。

  

动态创建组件


  PRADO

  允许开发者在自己的PHP代码中实例化组件。组件可以通过调用一个静态类方法Application::createComponent($type)来被实例化,该方法的参数$type 指明了要创建的组件的名称。组件也可以使用new 操作符来实例化。这两者方法的区别是:前者会使用一种缓存机制,下一次创建相同的组件时速度会快很多;而后者不会使用缓存机制,每次都要完全重复执行实例化的步骤。通常情况你应该使用TApplication::createComponent($type) 来实例化(如果你想了解更多,请参考下面的注释)。

  如果新创建的组件是一个控件,那么可以通过调用把这个控件作为其他控件的子控件。注意,如果你需要指定这个控件的ID,应该在将它添加作为其他控件的子控件之前就指定ID;否则的话框架会自动为它分配一个ID,而且这个ID是不能更改的。

  注:如果在构造函数中使用或申请了资源句柄的话,只能使用 new 操作符来实例化。因为PRADO使用了缓存机制来实例化组件,因此如果在构造函数中使用了资源句柄的话,下次实例化的时候从缓存读出来的数据中的资源句柄部分依然对应着原来的那块内存地址,这样就极容易导致系统崩溃。所以如果你要设计一个自己的组件,也尽可能的不要在构造函数中使用和申请资源句柄,而是应该把这些代码组织在一个别的方法中,在页面的OnInit事件或其它事件中调用。一般来说构造函数只需要实现简单的变量初始化即可。在PRADO的核心代码中,所有的组件的构造函数都没有使用到资源句柄。你在开发自己的组件的时候,可以参考一下它们的源代码。


 2.1.3  访问组件属性

  PHP 5 使用了一种很好的方式来访问组件的属性。你可以把一个组件的属性当作组件的成员变量来使用。比如要设置TButton 控件的Text 属性,你可以使用$button->Text="xxx"的代码,这里$button 代表了控件的实例。对于控件来说,你还可以使用它的ID路径来访问属性。假定现在HomePage页面有一个子控件MenuBar ,MenuBar 控件有一个子控件HyperLink ,那么在页面环境中,可以使用的代码$this->MenuBar->HyperLink->NavigateUrl来读取HyperLink 控件的NavigateUrl 属性。

  注意,由于PHP5.0中的一个BUG,如果你需要设置一个属性的值,那么你必须首先通过它的控件的ID路径来获得控件,然后再来设置这个属性的值。在上面这个例子中,需要用下面两行代码来设置NavigateUrl 属性。

 $link=$this->MenuBar->HyperLink;
$link->NavigateUrl="...";

  如果直接使用 $this->MenuBar->HyperLink->NavigateUrl 来设置属性值会产生一个错误。但是你还可以下面这段代码来设置属性的值,这样就可以避免那个错误了。

 $this->MenuBar->HyperLink->setNavigateUrl("...");

  2.1.4  使用事件

  事件响应函数通常在规格文件或者模板文件中指定给对应的事件,指定事件响应函数和指定属性的初始值是类似的。注意,在规格文件或者模板文件中指定的事件响应函数,必须在此规格文件或模板文件对应的组件中定义,它的语法如下:

 function handlerName($sender,$param)
{
...
}

  这里 $sender 指向的是触发这个事件的控件, $param 是事件的参数,它的内容取决于事件的类型。

  在编程的时候也可以使用TComponent::addEventHandler() 方法来动态的指定一个事件响应方法。

  你可以为一个事件指定多个响应方法。当这个事件被触发的时候,所有指定的响应方法都被自动调用。所以,PRADO实现的是多点派发事件触发机制。

  2.1.5  数据绑定(Data Binding)


  只有控件才可以数据绑定。

  你可以给控件的属性绑定一个表达式,当这个控件的dataBind() 方法被调用的时候,这个属性的值回自动被设置为这个表达式的值。数据绑定在开发数据组件时是非常有用的,这些组件的很多属性值都是来源于数据源提供的数据的。你可以在组件的规格或者模版文件中设定数据绑定,也可以在代码中设定。

  在模版中设定数据绑定的话,只要给属性的值指定一个有效的PHP表达式的字符串,并在前面加上一个# 作为前缀。比如在页面模版文件中使用如下的代码:

 <com:TLabel Text="#$this->Page->ID" />

  这段代码给TLabel 组件的Text 属性绑定了一个的表达式$this->Page->ID 。这个表达式的作用是获得当前控件所在页面的ID。注意,这个表达式中的$this指的是TLabel控件本身,因为$this所在上下文环境是在TLabel 中。

  在代码中要设定数据绑定,可以调用组件的bindProperty() 方法,这时候不需要在前面加上字符# 。

  注意,给属性绑定的表达式只有在dataBind() 被调用时才会计算该表达式的值,并把它赋值给属性。具体内容可以参考dataBind() 的相关文档。

  另外,如果在模板文件中你需要给一个属性赋初始值,而不是数据绑定的话,如果这个值是以#开头的,那么应该将#重复一次,就像PropertyName="##...." 一样。


2.1.6  PRADO 组件类树

  目前发布的 PRADO 包括如下所示的组件树,这些组件的属性,事件和类的方法在PRADO文档中都可以查到。

TComponent
    TAdodb
    TControl
        TExpression
        TForm
        TLiteral
        TPage
TPlaceHolder
        TRepeater
TRepeaterItem
        TStatements
        TWebControl
            TButton
            TCheckBox
                TRadioButton
            TDropDownList
            THyperLink
            TImage
                TImageButton
            TLabel
            TLinkButton
            TListBox
            TPanel
            TTextBox
                TDatePicker
                THtmlArea
            TValidationSummary
            TValidator
                TCompareValidator
                TCustomValidator
                TRangeValidator
                TRegularExpressionValidator
                    TEmailAddressValidator
                TRequiredFieldValidator



2.2  页面

  页面是 TPage 或者它的子类的一个实例。它是最高级别的组件,即没有父组件也不包含在一个容器中。PRADO的应用是由一些页面组成的。

  2.2.1  页面的生命周期

  理解页面的生命周期对掌握PRADO编程是非常重要的。

  首先我们要介绍一下postback的概念。我们把一个form的提交称之为postback,如果form的数据是提交给包含该form的页面的。postback可以被认为是由用户在客户端触发的一个事件。PRADO会区分出把postback事件交给哪一个服务器端的组件来响应。如果找到了这个组件,比如是一个TButton
,那么我们就把这个TButton 组件称为事件的发送者(sender)。

  页面在被请求调用的时候会经过几个状态。当一个页面是由于它发生了一个postback而被调用的时候,这个页面会经历以下的生命周期:

  1. 页面的创建:页面和它所有子组件是被递归创建的。框架根据各个组件的规格文件和模板文件的配置来初始化组件的属性。你一个可以重载页面的构造函数来做一些其他的初始化工作,比如给一些属性赋一些缺省值。但是需要注意的是,在这一步的时候,是不能够访问其他组件,因为组件之间的关系这时候还没有被建立。
  2. OnInit 事件: OnInit 事件会被广播给整个页面的组件树(也就是说所有的组件都会被触发OnInit事件)。可以重载页面的onInit() 方法或者给OnInit事件指定一个处理方法来做一些初始化的工作,比如建立数据库连接等等。这时候组件和组件的关系已经被建立了。
  3. 导入显示状态(Viewstate):将先前的显示状态导入到页面中。页面自己会将上次显示给用户看的状态保存起来。关于显示状态,下一章会有更详细的解释。
  4. 导入提交的数据:页面中的一些组件的属性会根据用户提交的数据而更新。比如,TTextBox 组件的Text 属性会被用户在此组件的文本输入框中输入的文本而更新。
  5. OnLoad 事件:在这个阶段,页面会设置为提交前用户看到的状态。OnLoad
    事件也会被广播给整个页面的组件树。同样也可以重载onLoad() 方法或者给OnLoad 事件指定一个处理函数。
  6. 导入提交的数据:一些在OnLoad 步骤创建的组件在这时候有机会导入提交的数据。
  7. 产生提交数据变化事件。如果一个组件的数据被用户改变了,那么就会机会产生一个事件来指明这个变化。比如用户改变了一个TTextBox 组件的文本输入框的值,那么这个TTextBox 组件就会触发一个OnTextChanged 事件。开发者能够为这个事件指定处理方法。
  8. 输入验证:如果事件的提交者需要验证,这时候页面注册的验证组件会来对应的数据。
  9. Postback事件:postback事件通过事件的发送者被触发。比如,用户点击了一个按钮引起了一次postback,那么这个按钮对应的TButton 组件就触发一个事件OnClick。你可以指定这个事件的处理函数来响应这个事件。
  10. OnPreRender 事件:在这一步,页面已经完成了被提交的数据的导入和postback事件的处理。OnPreRender 事件会被广播给整个页面的组件树 。在页面被绘制之前,你可以重载onPreRender() 函数或者给OnPreRender 事件指定一个事件处理函数。
  11. 整个页面的组件树的显示状态被保存在一个固定的存储空间(比如表单的隐藏字段,session,或者数据库中)。
  12. 通过递归的方式页面类来显示这个页面,页面中的组件会自己显示自己(意思是说每一个组件都会负责显示它自己)。通常情况下,组件会在对应所在模板的位置上来显示自己。你也可以重载TComponent 的render() 方法来自己控制组件的显示。
  13. OnUnload 事件:页面和它所有的子组件从内存中被释放。同样,这个事件也会被广播给整个页面的组件树。你可以通过重载onUnload() 函数或者给OnUnload 事件指定一个处理函数来完成一些清除工作,比如断开数据库的连接等等。

  当页面是第一次被请求的时候,上述的生命周期会简单一些。具体来说,导入显示状态,导入提交的数据,产生提交数据变化事件,输入验证和postback事件这几个状态是没有的。



(待续)


webasp.net