问题回顾
最近在研究一个DNN模块,其中有一个弹出界面是直接从DotNetNuke.Framework.PageBase继承来实现的。之前在DNN老版本上貌似是可以跑起来的,但是最近把它重新部署到DNN6和DNN7上时页面却崩溃了。以下是对应的错误信息:
StackTrace:
Message: DotNetNuke.Services.Exceptions.ModuleLoadException: The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases. ---> System.Web.HttpException: The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases. at System.Web.UI.ControlCollection.Add(Control child) at DotNetNuke.UI.Utilities.ClientAPI.RegisterDNNVariableControl(Control objParent) at DotNetNuke.UI.Utilities.ClientAPI.get_ClientVariableControl(Page objPage) at DotNetNuke.UI.Utilities.ClientAPI.GetClientVariableList(Page objPage) at DotNetNuke.UI.Utilities.ClientAPI.RegisterClientVariable(Page objPage, String strVar, String strValue, Boolean blnOverwrite) at DotNetNuke.UI.Utilities.ClientAPI.RegisterClientReference(Page objPage, ClientNamespaceReferences eRef) at DotNetNuke.UI.Utilities.ClientAPI.RegisterClientReference(Page objPage, ClientNamespaceReferences eRef) at DotNetNuke.UI.Utilities.DNNClientAPI.EnableMinMax(Control objButton, Control objContent, Int32 intModuleId, Boolean blnDefaultMin, String strMinIconLoc, String strMaxIconLoc, MinMaxPersistanceType ePersistanceType, Int32 intAnimationFrames, String strPersonalizationNamingCtr, String strPersonalizationKey) in C:\DNN5Dev\Library\UI\Utilities\ClientAPI.vb:line 155 at DotNetNuke.UI.Utilities.DNNClientAPI.EnableMinMax(Control objButton, Control objContent, Int32 intModuleId, Boolean blnDefaultMin, String strMinIconLoc, String strMaxIconLoc, MinMaxPersistanceType ePersistanceType, Int32 intAnimationFrames) in C:\DNN5Dev\Library\UI\Utilities\ClientAPI.vb:line 149 at DotNetNuke.UI.Utilities.DNNClientAPI.EnableMinMax(Control objButton, Control objContent, Int32 intModuleId, Boolean blnDefaultMin, String strMinIconLoc, String strMaxIconLoc, MinMaxPersistanceType ePersistanceType) in C:\DNN5Dev\Library\UI\Utilities\ClientAPI.vb:line 141 at DotNetNuke.UI.Utilities.DNNClientAPI.EnableMinMax(Control objButton, Control objContent, Boolean blnDefaultMin, MinMaxPersistanceType ePersistanceType) in C:\DNN5Dev\Library\UI\Utilities\ClientAPI.vb:line 111 at DotNetNuke.UI.UserControls.LabelControl.Page_Load(Object sender, EventArgs e) in C:\DNN5Dev\Library\UI\UserControls\LabelControl.vb:line 243
在网上找了很多也简单查找了DNN中的源码,一直没有找到原因。最近在浏览DNN官网的论坛时无意中有个老外提及了这个问题,幸运的是这次有个善良的老外回答了这个问题。以下是那个老外(William Severance)的回答:
The RegisterClientVariable method requires that the page's form contain a hidden input control with id and name of "__dnnVariable". Add the following markup to your aspx page's form and I think you'll have this working:
<input id="__dnnVariable" runat="server" name="__dnnVariable" type="hidden" />
No doubt you may find other similar problems when hosting dnn controls outside of a module container on the Default.aspx page.
由此可见,如果想在非default.aspx页面中使用dnn的用户控件,那你必须在你的页面的form中增加一个id为__dnnVariable的隐藏的input元素。按照这个方法,我在我的那个页面中添加了上诉的隐藏input元素--结果界面显示正常了。
更多的思考
即使自定义的页面能够正常显示了,但是这些页面并没有把DNN一系列的CSS文件以及jQuery引入进来。由此这些界面的样式看上去特别别扭,那是不是还有改进的余地呢?
其实在遇到这个错误的时候,其实我想到了另外一个解决方案,下面是我的想法:
1、将页面中的内容封装进一个ascx用户控件中
2、在原有调用弹出页面的地方使用DNN原始支持的dnnModal.show来用弹出式div的方式显示ascx控件
3、将此控件定义为模块组件,重新build生成模块安装包
4、卸载原模块并重新安装该模块
由于时间原因该方式还没有试过,有兴趣的童鞋可以先试试 :)
参考:
http://www.dnnsoftware.com/forums/forumid/118/threadid/330351/scope/posts/threadpage/2