基于DotNetNuke的动态窗体支持(一)


我在使用了DotNetNuke之后,对其中的UserDefinedTable模块比较感兴趣,并且认真的研究了 UserDefinedTable的数据结构和代码,认为这个模块的开发模式非常不错,于是,就基于这个模块,做了一些扩展的工作;和两年前基于 Joolma的一个FacileForms所做的工作有点类似,就是希望以列表式、灵活展示的方式,让用户可以去定义自己的数据结构,无论是列表、展示还是查询,都希望相对比较方便一些。其实,类似的模块,在DotNetNuke、Drupal、Joomla里面都有相若的例子,可见,对于CMS来说,这样的需求,是较为普遍的,一个更为“开放”的模块,对于用户来说,其实更容易接受和扩展。

  这里我所讲的东西,其实和DotNetNuke关系好像并不是太大,其实,都是ASP.Net的东西。

  对比一下UDT、FacileForms等模块,其实已经是相当不错了:支持较为丰富的数据类型、数据结构设计也非常合理,存储和查询做的也非常好——其实我现在对UDT的理解还是在3.3.7基础上的,后面升级了很多,但是都没有时间详细的去看。

  不过,有一个问题就是,我觉得我们在日常生活中所使用的Forms,“零碎”更多,比如说,要增加什么颜色的 Title、什么Banner、什么字体等等,所以,我觉得UserDefinedTable本来已经做得很好了,但是在这些“零碎”上,基本上却没有什么扩展性,于是,在我开发的Form里面,我希望界面的定义可以更加灵活一些,比如说,完全由用户自己定义界面,美工使用DreamWeaver等工具去定义就可以了,而不需要和程序人员去沟通;只要在设计完成界面之后,在特定的地方,插入一些标识符(TAG),然后,模块就可以对这些标识符进行解析,并且插入相应的控件。如果可以这样做的话,我们就将所有的界面工作可以完全的丢给美工,让美工去处理就好了

至于UDT和Joomla的FacileForms为什么没有这么做,我还不太理解;下面,我来说一下我这样做的思路。

  1、ASP.Net已经支持动态加载用户控件,用户控件基本上是一个ascx的文件,对于美工来说,这个可以是一个html文件,只要在设计完成之后,修改一下扩展名就可以了。所以,对于Form来说,每一个动态的Form,对应一个唯一的ascx文件;

  2、ASP.Net在加载完成ascx文件之后,可以读取ascx文件中的server标记,这就为加载完成之后,立即对服务器控件进行解析提供了方法,举一个例子,我们用下面的方法加载一个ascx控件:

Code
  DimucASControl
  DimstrFormatFileName="/Portals/0/RedstartForm/371_1.ascx"
  uc=CType(Page.LoadControl(strFormatFileName), Control)

  上面的代码,我们已经用ASP.Net在运行时动态加载了一个用户控件,这个用户控件,可以由我们的美工人员进行定义(当然,在实际的代码中,strFormatFileName是动态产生的,可以根据当前的模块ID等进行动态绑定),当我们加载完了用户控件之后,马上用代码去遍历用户控件,找到我们定义的标识符,然后,再进行处理。代码如下:

      ForEachcAsControlInuc.Controls        Ifc.GetType.ToString().Equals("System.Web.UI.WebControls.PlaceHolder")Then
          DimstrControlNameAsString=c.ID.Replace("__","")
          ForEachobjFieldAsRedstartFormFieldInfoIncolFields
            IfstrControlName.ToUpper()=objField.FieldName.ToUpper()Then
                objCtl=MyControls.Add(objField.FieldTitle,objField.FieldType,objField.KeyID,objField.FieldName,_
                PublicFunction.FormatParameter(objField.DefaultValue,strRowID,strParentID,strRelateRowID),_
                objField.Required,bEnabled,objField.IsReadOnly,PublicFunction.FormatParameter(objField.Extended,strRowID,strParentID,strRelateRowID),_
                objField.CssEnable,objField.CssDisable)
              c.Controls.Add(objCtl)
              ExitFor
            EndIf
          Next
        EndIf
      Next

上面的代码,是遍历我们动态加载的ascx控件中的PlaceHolder控件,如果找到PlaceHolder控件的话,则判断,是不是我们已经对之有了定义,如果有了定义的话,则为其增加子控件,这样,就完成了用户界面的遍历过程。

  上面的例子中,由于我们只是在动态加载的控件中找PlaceHolder控件,而对其他任何的控件(无论是服务器端,还是客户端)都置之不理,所以,对于ascx文件来说,我们并不在乎其他的东西,比如样式、风格、字体、图片等等,尽可以全部都放到这个ascx文件中,我们的解析程序都对之视而不见。比如,我们可以画一个Table,让控件在Table的某一个单元格中,所需要做的,只是在该单元格的代码中放置下面这样的一个标识符而已:

  <asp:PlaceHolder runat="server" ID="__RowName"></asp:PlaceHolder>  <!--名称-->

  当然,我们在PlaceHolder的ID的前面增加了双下划线(__),这是为了和控件的ID做一个区别(因为我们在PlaceHolder所动态增加的控件是没有下划线的,如果ID重复则会出现错误;)

  还有一点需要说明的是,在上面的遍历ascx子控件的代码中,我们并没有对子控件做子控件的遍历,也就是说,如果我们的ascx控件中包含如下的内容的话:

  <asp:Table runat="server" id="tblAll">
     <TableRow>
       <TableCell>
         <asp:PlaceHolder runat="server" ID="__RowName"></asp:PlaceHolder>  <!--名称-->
       </TableCell>
     </TableRow>
  </asp:Table>


  我们遍历到tblAll这个控件的时候,就不会往下去遍历了;这也就要求美工在设计ascx的时候,必须要将我们的 PlaceHolder控件放在顶层;当然,我相信这个对美工不会造成障碍,因为他们在设计的时候,理论上应该不会使用到服务器端的Table控件,他们使用Client端的<table>应该已经足以完成所有的设计工作了。

  我对UDT模块的扩展后,将“是否自定义界面”做成一个Settings,放在模块设置中,这样,一个模块是用系统自行产生的界面(相对比较死板),还是用动态加载ascx的方式产生界面(可以由美工设计,相对比较灵活),就可以由模块的管理员进行设置了。

  这个系列的后面,我们谈一下产生的控件的过程,和一些其他的要素等等


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3