在DNN模块中如何调用DNN/Controls下的用户控件

      最近在基于DNN开发一个网站,发现一件有趣的事情。
      由于业务逻辑有许多可以抽取的共性,我将一个用于筛选的功能做成了用户控件(UserControl,为了方便叙述,我们称它为Filter),并把它放在DNN的Controls目录下,即\DotNetNuke\controls,以便各个模块均可调用。这个用户控件很简单,就是一些下拉框,用于对数据进行查询,我将下拉框的SelectedValue封装成公共属性,这样就可以从外部调用了。比如,里面的一个属性是这样写的:
        '项目名称
        Public Property ProjectName() As String
            Set(ByVal Value As String)
                _ProjectName = Value
            End Set
            Get
                Return Me.sltProjectName.SelectedValue
            End Get
        End Property
      这是几句VB.NET代码,当读取这个公共属性的时候,我就返回相应的下拉框(sltProjectName)的选中值(SelectedValue)。
      很简单。

      然后在自己编写的DNN模块(DesktopModules)中,这样使用它:
      1、首先,在VS的“HTML”视图中,在顶部添加对它的引用:
            <%@ Register TagPrefix="dnn" TagName="CSBSGFilter" Src="~/controls/CSBSGFilter.ascx" %><%@ Register TagPrefix="dnn" TagName="CSBSGFilter" Src="~/controls/CSBSGFilter.ascx" %><%@ Register TagPrefix="dnn" TagName="Filter" Src="~/controls/Filter.ascx" %>
      2、然后,在HTML中合适的位置,添加一个引用实例,比如在一个单元格中:
            <TD><dnn:Filter id="filter" runat="server"></dnn:Filter></TD>
      3、OK,这样我已经在页面上加入了该用户控件,切换到“设计”视图,发现显示也正常,控件上没有红色粗体字体提示说“创建控件时出错”。
      4、下面该开始书写代码了,我得调用这个用户控件的公共属性做事吖,否则我写它干什么?于是,切换到代码页,在类体中创建一个该用户控件的私有实例:
            DotNetNuke.UI.UserControls.Filter filter = new DotNetNuke.UI.UserControls.Filter();
      是的,这句话是要手工加上的,因为用户控件不像VS工具箱里面的Label、Button一样,只要拖到页面上,代码中就会创建一个实例。
      5、到现在为止,一切都很正常。下面一句调用该用户控件的公共属性:
            string projectName = filter.ProjectName;
      这看起来也没有什么问题,公共属性嘛,可以调用。编译的时候也通过了,但运行的时候,读取用户控件的属性值之后,点击“提交”按钮时,DNN却捕获了异常,经典错误:“未将对象设置引用到对象实例”。
      
      怎么回事?经过调试、跟踪,发现当页面装载的时候,用户控件里面的下拉框们还都正常(因为我在用户控件的PageLoad事件中对它们进行了绑定),但“提交”(指的是调用用户控件的页面提交)时,在Button的Click事件中,执行上述第5步操作时,引发了该异常,继续跟下去,发现当我欲:
      Return Me.sltProjectName.SelectedValue
      的时候,下拉框控件sltProjectName适时地变成了NoThing……

      我@-@~~了。怎么回事?页面装载时绑定它们还正常,怎么一提交就没有了?(注意,由于其他原因,我没有让下拉框AutoPostback = true)
      后来经过高手的指点,告知原因出在创建实例的这句话:
            DotNetNuke.UI.UserControls.Filter filter = new DotNetNuke.UI.UserControls.Filter();
      把它改成仅声明,不进行new操作:
            DotNetNuke.UI.UserControls.Filter filter;
      直到需要的时候用这种形式去获取对象实例:
            filter = this.FindControl("filter") as Filter;
      然后再调用属性,就正常了。
      原因是什么?据高手说,这句话看上去虽然很无辜,但由于在HTML代码中已经写了:
            <dnn:Filter id="filter" runat="server"></dnn:Filter>
      这就相当于已经创建了一个实例,只需声明一下,与之匹配上就可以了,而这句话又创建了一个实例,覆盖了原本存在的那个,就导致了错误。(大致如此罢,我没有搞很明白,这块挺复杂的)
      总之,记在这里罢,究竟是什么原因,欢迎大家拍砖。以后有相同迷惑的朋友也可以做一个参考,遇到这种情况百思不得其解的时候,试试这种方法,或许能够解决。

你可能感兴趣的:(用户)