2009-04-28 59 views
27

我在.NET 2.0/3.0之前的版本中使用过FindControl。现在看来,出于某种原因,我的控件的ID得到了一个名为分配的时髦。例如,我将一个id“cbSelect”分配给一个复选框,但FindControl没有找到它。当我查看HTML时,它被分配为ctl00_bodyPlaceHolder_ctl02_cbSelectASP.Net FindControl不工作 - 怎么回事?

我还没有找到一个FindControl的例子提到。实际上,每个人似乎都只是使用像普通的查找控制。

那么,我做错了什么? .Net是否改变?任何人都可以为我阐明这一点,这真是令人沮丧!

回答

25

您可能正在使用MasterPage或用户控件(ascx),这就是客户端id更改的原因。想象一下,您在母版页中使用与页面中相同的ID进行控制。这会导致冲突。 id更改确保所有ClientID属性在页面上都是唯一的。

使用MasterPages时,FindControl需要特别注意。看看ASP.NET 2.0 MasterPages and FindControl()。 FindControl在naming container内工作。 MastePage和页面是不同的命名容器。

+9

微软实施这个的方式是这样的一个笑话,它应该只是工作。哦,你有一个主页?大约500个嵌套母版页如何?该方法应该算出来,并且找到控制周期的必要条件。 – 2013-05-19 01:51:19

+0

你知道你在同一个想法中使用“应该”和“微软”吗? – user1566694 2016-12-13 20:32:28

1

当它呈现html时,ASP.NET会将所有控件ID与命名容器(用户控件等)的ID作为前缀一直回溯到文档根目录。这确保了所有ID对于后贴等都是唯一的。

这不影响使用FindControl,您应该在原始标记中使用ID。

8

我有运气还算不错解决此问题,工作中“最”的情况下用一个简单的扩展方法

你可以在任何你认为最好的高级容器控件上调用它,包括如果你想扫描整个控件层次结构的Page本身。

private static Control FindControlIterative(this Control control, string id) 
{ 
    Control ctl = control; 

    LinkedList<Control> controls = new LinkedList<Control>(); 

    while(ctl != null) 
    { 
    if(ctl.ID == id) 
    { 
     return ctl; 
    } 
    foreach(Control child in ctl.Controls) 
    { 
     if(child.ID == id) 
     { 
     return child; 
     } 
     if(child.HasControls()) 
     { 
     controls.AddLast(child); 
     } 
    } 
    ctl = controls.First.Value; 
    controls.Remove(ctl); 
    } 
    return null; 
} 
8

您可以使用递归来编写扩展器以查找页面上的任何控件。 这可能在某些Util/Helper类中。

public static Control FindAnyControl(this Page page, string controlId) 
    { 
     return FindControlRecursive(controlId, page.Form); 
    } 

    public static Control FindAnyControl(this UserControl control, string controlId) 
    { 
     return FindControlRecursive(controlId, control); 
    } 

    public static Control FindControlRecursive(string controlId, Control parent) 
    { 
     foreach (Control control in parent.Controls) 
     { 
      Control result = FindControlRecursive(controlId, control); 
      if (result != null) 
      { 
       return result; 
      } 
     } 
     return parent.FindControl(controlId); 
    } 
7

在控件集合中搜索控件时,请始终使用您分配给控件的标识,而不是在源标记呈现中看到的标识。如果FindControl()没有找到你知道存在的控件,那么很有可能你没有在控件层次结构的右边分支中搜索。递归函数对我来说是成功的。

这里是我的就是我使用VB.NET 3.5例如:

Function FindControlRecursive(ByVal ctrl As Control, ByVal id As String) As Control 
    Dim c As Control = Nothing 

    If ctrl.ID = id Then 
     c = ctrl 
    Else 
     For Each childCtrl In ctrl.Controls 
      Dim resCtrl As Control = FindControlRecursive(childCtrl, id) 
      If resCtrl IsNot Nothing Then c = resCtrl 
     Next 
    End If 

    Return c 
End Function 

这里是我怎么会在局部我的基地页类实现这个功能的例子:

Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm) 
+1

+1,因为没有看到你的我已经在C#中用相同的方法实现它: ``````````空值; if(ctl.ID == id)return ctl; (ctl.Controls.Count> 0) foreach(ctl.Controls中的Control sc) 控制fnd = FindControlRecursive(sc,id); if(fnd!= null)return fnd; } return null; }` – gkakas 2013-11-17 10:04:55

3

这是VB。NET代码工作对我来说:

<Extension()> _ 
Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control 
    If controlToStartWith Is Nothing Then Return Nothing 
    If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith 
    For Each childControl As Control In controlToStartWith.Controls 
     Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind) 
     If resCtrl IsNot Nothing Then Return resCtrl 
    Next childControl 
    Return Nothing 
End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control 

信用去乔治最初的VB.NET代码。我只修改它少许,有2个功能改变:如果/当null /没有任何东西作为输入控件传递时,我的错误不会发生错误,并且我的作为扩展实现。我的其他3个较小的更改不影响功能,但对我来说,它们是代码简化。但我知道这很主观。

那么这种方法可以用于:

Dim c1 As Control = Page.FindChildControlById("aspControlID") 

如果你想将它转换成一个特定的子类控制的,就像这样:

Dim c1 As Control = Page.FindChildControlById("aspControlID") 
Dim c As HyperLink = TryCast(c1, HyperLink) 

更新:我的功能现在名为'FindChildControlById'(以前是'FindMiControl')。我更喜欢SpeedNet的建议。