【问题标题】:Accessing nested controls in custom validator访问自定义验证器中的嵌套控件
【发布时间】:2012-11-27 11:42:58
【问题描述】:

如何从自定义验证器访问嵌套在页面中多个级别的 asp.net 控件?

具体来说,我正在生成位于占位符内的下拉列表,该占位符在中继器内,在另一个中继器内,在另一个占位符内。

我需要访问所有下拉框的选定值以相互比较。

我当前的解决方案是遍历每个控件中的所有控件,直到我深入到可以访问下拉列表的:

    For Each g As Control In sender.Parent.Controls
        If g.GetType().ToString.Equals("System.Web.UI.WebControls.Repeater") Then
            For Each k As Control In g.Controls
                If k.GetType().ToString.Equals("System.Web.UI.WebControls.RepeaterItem") Then
                    For Each l As Control In k.Controls
                        If l.GetType().ToString.Equals("System.Web.UI.WebControls.Repeater") Then
                            For Each p As Control In l.Controls
                                If p.GetType().ToString.Equals("System.Web.UI.WebControls.RepeaterItem") Then
                                    For Each n As Control In p.Controls
                                        If n.GetType().ToString.Equals("System.Web.UI.WebControls.PlaceHolder") Then
                                            For Each c As Control In n.Controls
                                                If c.GetType().ToString.Equals("System.Web.UI.WebControls.DropDownList") Then

                                                'Add the dropdownlist to an array so that I can use it after all drop down lists have been added for validation.

这似乎完全是在浪费资源。有没有更好的方法从自定义验证器访问这些控件?

【问题讨论】:

    标签: asp.net


    【解决方案1】:

    我相信您可以使用$ 连接容器名称以访问嵌套控件;像这样:

    ControlToValidate="panel1$usercontrol1$otherusercontrol$textbox1"
    

    这确实会导致验证器执行内部 FindControl() 调用,这有点昂贵,因此您应该谨慎使用这种方法。

    一般来说,访问其他容器内深度嵌套的控件并不是一个好主意。您应该将这些控件视为页面/控件的私有成员,而不是通过这种方式访问​​它们。仅当您真的、真的必须时才使用上述方法。

    编辑:这可能不是完美的解决方案,但我会这样做。创建一个新的 DropDownListX 控件(从 DropDownList 派生),该控件抓取页面并检查页面是否实现了您创建的新自定义接口。此接口可用于向页面注册控件,然后您的验证器可以通过此列表并验证每个注册的控件。比如:

    interface IValidationProvider
    {
        void RegisterForValidation ( Control oCtrl );
    }
    

    您的页面应实现此接口。然后在你的新 DropDownListX 控件中:

    protected override void OnLoad ( EventArgs e )
    {
        IValidationProvider oPage = Page as IValidationProvider;
    
        if ( oPage != null )
            oPage.RegisterForValidation ( this );
    }
    

    然后在页面中,当验证发生时,你可以遍历验证列表中的控件列表,并一一验证。您的自定义验证器不会有单个 ControlToValidate 控件名称,但这似乎适合您,因为您有 1 个验证器来验证嵌套中继器内的多个控件。

    此解决方案使您能够完全跳过当前的深度循环 - 如果您有一个需要验证的控件,它将自行注册,否则页面中的列表将为空且无需检查任何内容。这也避免了对控件名称进行字符串比较,因为控件不需要被搜索——它们在需要时注册自己。

    【讨论】:

    • 我不知道控件的id,因为它们是通过多个转发器在aspx文件中生成的。
    • @KevinWasie 啊,那会更难。您是否在转发器中有用户控件,或者您只是将控件直接放在项目模板中?
    • 直接在项目模板内
    • 我更新了答案 - 看看这种方法是否适合你。我过去做过这种设置,效果很好,而且比使用递归循环搜索控件要快很多。当您有大量传入请求时,这会产生很大的不同。
    • 哇,太酷了。我可以想到这个框架将有益的多个实例。谢谢!
    【解决方案2】:

    您是否尝试过递归获取控件?

    private Control FindControlRecursive(Control root, string id) 
    { 
        if (root.ID == id)
        { 
            return root; 
        } 
    
        foreach (Control c in root.Controls) 
        { 
            Control t = FindControlRecursive(c, id); 
            if (t != null) 
            { 
                return t; 
            } 
        } 
    
        return null; 
    } 
    

    【讨论】:

    • 仍然会消耗系统。 @xxbbcc 方法将对流量进行扩展。谢谢。
    猜你喜欢
    • 2018-04-03
    • 1970-01-01
    • 2011-03-17
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    相关资源
    最近更新 更多