在ASP.NET 4.0以前咱们老是要为控件的ClientID头疼,好比明明一个叫lblName的Label放在一个叫作grd的GridView里面后,在页面上改Label的ID就变成了诸如grd_clt02_lblName的一长串字符串,若是咱们在前台想在使用JS的时候找到该Label,咱们不得不用到C#脚原本得到该Label在前台的确切ID,诸如:javascript
1 <script type="text/javascript"> 2 var lblName = document.getElementById("<%=lblName.ClientID %>"); 3 </script>
在ASP.NET 4.0中的每一个控件上都多了一个叫作ClientIDMode的属性,这就是解决上面获取控件ID难的解决方案。这个属性有四个可选值,根据所选值的不一样它能够控制页面上生成控件的ID格式。java
下面就让咱们来了解下ClientIDMode属性的四个值:spa
1,AutoID:code
当控件的ClientIDMode选中为AutoID时,该控件的ClientID 值是经过串联每一个祖先容器控件(诸如GridView、ListView、LoginView等就是容器性控件)的ID和父容器控件的ID和其自己的ID 值生成的,固然若是该控件没有在任何容器控件中其ClientID 值就是其自己的ID值,不会作任何更改。 另外若是该控件所在的父容器控件或祖先容器控件有些是显示多个数据行的容器控件(例如GridView、ListView就是显示多数据行的容器控件),那么还将在这些容器控件的ID值的后面会插入一个递增的行号格式。 各部分之间如下划线字符 (_) 分隔。 可见在 ASP.NET 4 以前的版本中使用的就是AutoID方案来生成控件的ClientID 值。server
好比下面这个GridView里面就有一个名叫Label1的ID,咱们将Label1的ClientIDMode设置为了AutoID:blog
1 Code highlighting produced by Actipro CodeHighlighter (freeware) 2 http://www.CodeHighlighter.com/ 3 4 --><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 5 AutoGenerateColumns="False" 6 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 7 Width="676px" PageSize="5" ClientIDMode="AutoID" > 8 <Columns> 9 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 10 <ItemTemplate> 11 <asp:Label ID="Label1" runat="server" 12 Text='<%# Bind("[Account Number]") %>' ClientIDMode="AutoID"></asp:Label> 13 </ItemTemplate> 14 </asp:TemplateField> 15 </Columns> 16 </asp:GridView>
该GridView生成的客户端HTML代码就是:继承
1 Code highlighting produced by Actipro CodeHighlighter (freeware) 2 http://www.CodeHighlighter.com/ 3 4 --><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 5 <tr> 6 <th scope="col">Account Number</th> 7 </tr> 8 <tr> 9 <td> 10 <span id="grd_Account_ctl02_Label1">1060</span> 11 </td> 12 </tr> 13 <tr> 14 <td> 15 <span id="grd_Account_ctl03_Label1">1200</span> 16 </td> 17 </tr> 18 <tr> 19 <td> 20 <span id="grd_Account_ctl04_Label1">1510</span> 21 </td> 22 </tr> 23 </table>
能够看到GirdView里面的Label造成了诸如grd_Account_ctl02_Label1格式的ClientID,而这正是:父容器ID(grd_Account)+"_"+行号格式(ctl02)+"_"+控件自身ID(ClientID)这种格式生成的。ip
2,Static:ci
当控件的ClientIDMode选中为Static时,该控件的ClientID 值就是其自己设置的 ID 属性值,其ClientID值不会受到父容器控件的影响。字符串
好比咱们把上面的代码稍做修改,将Label1的ClientIDMode属性改成Static:
1 Code highlighting produced by Actipro CodeHighlighter (freeware) 2 http://www.CodeHighlighter.com/ 3 4 --><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 5 AutoGenerateColumns="False" 6 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 7 Width="676px" PageSize="5" > 8 <Columns> 9 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 10 <ItemTemplate> 11 <asp:Label ID="Label1" runat="server" Text='<%# Bind("[Account Number]") %>' ClientIDMode="Static"></asp:Label> 12 </ItemTemplate> 13 </asp:TemplateField> 14 </Columns> 15 </asp:GridView>
运行后查看获得的HTML代码:
1 Code highlighting produced by Actipro CodeHighlighter (freeware) 2 http://www.CodeHighlighter.com/ 3 4 --><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 5 <tr> 6 <th scope="col">Account Number</th> 7 </tr><tr> 8 <td> 9 <span id="Label1">1060</span> 10 </td> 11 </tr><tr> 12 <td> 13 <span id="Label1">1200</span> 14 </td> 15 </tr><tr> 16 <td> 17 <span id="Label1">1510</span> 18 </td> 19 </tr> 20 </table>
看到了吗,GridView里每行的Label1的ClientID都以自身ID的值出现了,不会受到父级容器控件的ID影响,这样在前台使用JS时咱们就能通控件自己的ID值找到咱们想要的控件了。
此外使用Static后势必页面中会出现不少同名的控件ID,只要这些同名ID的控件处于页面的不一样层次(好比某一容器控件的内部和外部就是不一样层次)上那么就不会出现问题,可是若是页面同一层次上有多个同ID的控件,那么页面就会报错。
3,Inherit:
这个属性其实没什么好说的,若是控件的ClientIDMode选中为Inherit,那么表示该控件的ClientIDMode会使用父级容器控件的ClientIDMode值,若是父级容器控件的ClientIDMode也为Inherit,那么会使用更上层容器控件的ClientIDMode值,直到回溯到页面的ClientIDMode值为止,页面的ClientIDMode值默认为Predictable ,你能够在页面上的<%@ Page%>指令中对该值作更改。此外Inherit也是ASP.NET 4.0中全部控件的ClientIDMode属性的默认值。
4,Predictable:
首先我先说明下之因此最后写Predictable,是由于我发现控件的ClientIDMode为Predictable时生成ClientID的机制会很是复杂,要分好几个部分分别进行讨论,其中还有特殊状况,因此我在这里只能说尽可能将我发现的Predictable生成ClientID的机制阐述清楚。
当控件的ClientIDMode选中为Predictable时,该控件的ClientID 值是经过串联父容器控件(诸如GridView、ListView、LoginView等就是容器性控件)的 ClientID 值生成的。另外若是该控件是在显示多个数据行的父容器控件或祖先容器控件中(例如GridView、ListView就是显示多数据行的容器控件),则还会在该控件ClientID 值的末尾添加 ClientIDRowSuffix 属性中指定的数据字段的值。 对于 GridView 控件,ClientIDRowSuffix 属性能够指定多个数据字段。 若是 ClientIDRowSuffix 属性为空白,则在末尾添加递增的行号,而非数据字段值。 各部分之间如下划线字符 (_) 分隔。
<1>若是父容器控件的ClientIDMode值为AutoID
- 若是父容器控件或祖先容器控件为显示多个数据行的容器控件,那么该控件的ClientID格式为:[父/祖先容器控件的ID+"_"+[行号格式+"_"]]+该控件自身ID+"_"+[ClientIDRowSuffix],其中ClientIDRowSuffix部分是什么后面会单独说明,其中:[父/祖先容器控件的ID+"_"+[行号格式+"_"]],就是该控件自身ClientIDMode值继承父容器控件ClientIDMode值AutoID生成的ClientID结果,其中的[行号格式+"_"]部分是否存在依赖于[父/祖先容器控件]部分是不是显示多个数据行的容器控件(这里不明白请看前面的AutoID部分)。
- 若是父容器控件或祖先容器控件都不是显示多个数据行的容器控件,那么该控件的ClientID格式为:[父/祖先容器控件的ID+"_"]+该控件自身ID,可见这个格式就是该控件自身ClientIDMode值继承父容器控件ClientIDMode值AutoID生成的ClientID结果(这里不明白请看前面的AutoID部分)。
下面我就举一个父容器控件是多数据行容器控件且其ClientIDMode为AutoID的例子,将上面的代码再作更改,将Label1的ClientIDMode属性值改成Predictable,而且设置其父容器控件grd_Account的ClientIDMode为AutoID:
以上是MSDN的说法,可是通过试验,我发现Predictable的特性更应该是用这么个式子来表达:
Inherit[+"_"+ClientIDRowSuffix]
意思就是说,若是一个控件的ClientIDMode选中为Predictable,那么在ASP.NET生成该控件的ClientID时首先会去看该控件所属的父容器控件的ClientIDMode是什么值,而后先用该控件父容器控件的ClientIDMode规则生成该控件自己的ClientID,最后若是该控件所属的父容器控件或祖先容器控件是显示多个数据行的容器控件,还会根据父容器控件或祖先容器控件的ClientIDRowSuffix属性的值在该控件已生成的ClientID后面加上一个后缀字符串。
下面将几种状况逐一列出来单独解释:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 2 AutoGenerateColumns="False" 3 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 4 Width="676px" PageSize="5" ClientIDMode="AutoID" > 5 <Columns> 6 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 7 <ItemTemplate> 8 <asp:Label ID="Label1" runat="server" Text="Logged" ClientIDMode="Predictable"></asp:Label> 9 </ItemTemplate> 10 </asp:TemplateField> 11 </Columns> 12 </asp:GridView>
其生成的HTML代码为:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="grd_Account_ctl02_Label1_0">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="grd_Account_ctl03_Label1_1">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="grd_Account_ctl04_Label1_2">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成的Label的控件的ID诸如:grd_Account_ctl02_Label1_0正是上面所述格式:父容器控件的ID(grd_Account)+"_"+行号格式(ctl02)+"_"+该控件自身ID(Label1)+"_"+[ClientIDRowSuffix](0)。
<2>若是父容器控件的ClientIDMode值为Static
- 若是父容器控件或祖先容器控件为显示多个数据行的容器控件,那么该控件的ClientID格式为:该控件自身ID+"_"+[ClientIDRowSuffix],其中ClientIDRowSuffix部分是什么后面会单独说明,其中:该控件自身ID,就是该控件自身ClientIDMode值继承父容器控件ClientIDMode值Static生成的ClientID结果(这里不明白请看前面的Static部分)。
- 若是父容器控件或祖先容器控件都不是显示多个数据行的容器控件,那么该控件的ClientID格式为:该控件自身ID,可见这个格式就是该控件自身ClientIDMode值继承父容器控件ClientIDMode值Static生成的ClientID结果(这里不明白请看前面的Static部分)。
下面我就举一个父容器控件是多数据行容器控件且其ClientIDMode为Static的例子,将上面的代码再作更改,将Label1的ClientIDMode属性值改成Predictable,而且设置其父容器控件grd_Account的ClientIDMode为Static:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 2 AutoGenerateColumns="False" 3 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 4 Width="676px" PageSize="5" ClientIDMode="Static" > 5 <Columns> 6 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 7 <ItemTemplate> 8 <asp:Label ID="Label1" runat="server" Text="Logged" ClientIDMode="Predictable"></asp:Label> 9 </ItemTemplate> 10 </asp:TemplateField> 11 </Columns> 12 </asp:GridView>
其生成的HTML代码为:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="Label1_0">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="Label1_1">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="Label1_2">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成的Label的控件的ID诸如:Label1_0正是上面所述格式:该控件自身ID(Label1)+"_"+[ClientIDRowSuffix](0)。
<3>若是父容器控件的ClientIDMode值为Predictable
- 若是父容器控件或祖先容器控件为显示多个数据行的容器控件,那么该控件的ClientID格式为:父容器控件的ClientID+"_"+该控件自身ID+"_"+[ClientIDRowSuffix],其中ClientIDRowSuffix部分是什么后面会单独说明,可见这种状况才属于MSDN上所说的格式。
- 若是父容器控件或祖先容器控件都不是显示多个数据行的容器控件,那么该控件的ClientID格式为:父容器控件的ClientID+"_"+该控件自身ID,可见这种状况才是MSDN上所说的格式。
下面我就举一个父容器控件是多数据行容器控件且其ClientIDMode为Predictable的例子,将上面的代码再作更改,将Label1的ClientIDMode属性值改成Predictable,而且设置其父容器控件grd_Account的ClientIDMode也为Predictable:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 2 AutoGenerateColumns="False" 3 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 4 Width="676px" PageSize="5" ClientIDMode="Predictable" > 5 <Columns> 6 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 7 <ItemTemplate> 8 <asp:Label ID="Label1" runat="server" Text="Logged" ClientIDMode="Predictable"></asp:Label> 9 </ItemTemplate> 10 </asp:TemplateField> 11 </Columns> 12 </asp:GridView>
其生成的HTML代码为:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="grd_Account_Label1_0">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="grd_Account_Label1_1">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="grd_Account_Label1_2">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成的Label的控件的ID诸如:grd_Account_Label1_0正是上面所述格式:父容器控件的ClientID(grd_Account)+"_"+该控件自身ID(Label1)+"_"+[ClientIDRowSuffix](0)。
<4>若是父容器控件的ClientIDMode值为Inherit
这种状况没什么好说的,由于父容器控件的ClientIDMode值会继承其所在更上层的祖先容器控件的ClientIDMode值,继承后也属于上面三种状况之一。
最后来讲说ClientIDRowSuffix部分是什么,若是父容器控件或祖先容器控件是显示多数据行的容器控件(后面会讨论到若是控件的ClientIDMode为Predictable,在判断该控件是否在显示多数据行的容器控件中时,会有一种特殊的穿透现象),那么父容器控件或祖先容器控件会有个属性叫ClientIDRowSuffix,好比本例中的GridView的ClientIDRowSuffix属性,这个属性的做用是为设定ClientIDMode值为Predictable的子控件生成ClientID的后缀字符串(就是上面那些ClientID格式中的ClientIDRowSuffix部分):
若是 ClientIDRowSuffix 属性为空白,则在已生成的子控件ClientID末尾添加递增的行号并在行号前面加上下划线字符 (_) 分隔,好比上面的例子中因为都没有在GridView上设置ClientIDRowSuffix属性,因此ClientIDRowSuffix为空白,那么生成的子控件ClientID最末位都有诸如_0、_一、_2等的递增行号。
此外还能够设置ClientIDRowSuffix 属性值为父容器控件或祖先容器控件中DataSource数据源中的字段,这样生成子控件ClientID的后缀字符串为ClientIDRowSuffix 指定字段在该行的数据值,而且ClientIDRowSuffix 属性可指定多个DataSource数据源中的数据字段,那么在生成子控件ClientID时会将每一个数据字段在该行的值用下划线字符 (_) 进行分隔而后做为ClientID后缀字符串。
如今就举个例子,将上面的代码再作更改将Label1的ClientIDMode属性值改成Predictable,而且设置其父容器控件grd_Account的ClientIDMode也为Predictable,而且将grd_Account的ClientIDRowSuffix设置为数据源sds_account的Account Number字段:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 2 AutoGenerateColumns="False" 3 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 4 Width="676px" PageSize="5" ClientIDMode="Predictable" ClientIDRowSuffix="Account Number" > 5 <Columns> 6 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 7 <ItemTemplate> 8 <asp:Label ID="Label1" runat="server" Text="Logged" ClientIDMode="Predictable"></asp:Label> 9 </ItemTemplate> 10 </asp:TemplateField> 11 </Columns> 12 </asp:GridView>
其生成的HTML代码为:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="grd_Account_Label1_1060">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="grd_Account_Label1_1200">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="grd_Account_Label1_1510">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成子控件的ClientID的后缀字符串为Account Number字段在GridView上每行的值:1060、1200、1500,其再也不是递增的行号.
EX:最后Predictable还有一个很特别的特性:
当控件的ClientIDMode为Predictable且该控件在多个嵌套的容器控件中时,判断该控件是否在显示多数据行的容器控件中时,会具备层次穿透性,它不但会考察父容器控件,还会考察祖先容器控件。
下面就举个例子来讲明这种状况,首先grd_Account为显示多数据行的容器控件,它的ClientIDMode设置为Static,在它内部有一个ID为LoginView1的LoginView,咱们知道LoginView也是容器性控件,只不过它不是显示多数据行的容器控件,这里设置LoginView1的ClientIDMode属性为Predictable,在LoginView1里面再放置一个ID为Label1的Label,它的ClientIDMode没有设置,因此其值也默认继承为Predictable,下面是代码:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><asp:GridView ID="grd_Account" runat="server" AllowPaging="True" 2 AutoGenerateColumns="False" 3 DataKeyNames="Account Number" DataSourceID="sds_account" Height="63px" 4 Width="676px" PageSize="5" ClientIDMode="Static" > 5 <Columns> 6 <asp:TemplateField HeaderText="Account Number" SortExpression="Account Number"> 7 <ItemTemplate> 8 <asp:LoginView ID="LoginView1" runat="server" ClientIDMode="Predictable" > 9 <LoggedInTemplate> 10 <asp:Label ID="Label1" runat="server" Text="Logged"></asp:Label> 11 </LoggedInTemplate> 12 </asp:LoginView> 13 </ItemTemplate> 14 </asp:TemplateField> 15 </Columns> 16 </asp:GridView>
能够看到在嵌套层次结构中,因为LoginView1所属的父容器控件grd_Account是显示多数据行的容器控件,因此LoginView1的ClientID应该是诸如:LoginView1_0、LoginView1_1等有ClientIDRowSuffix部分的格式,这没有问题,可是按道理来讲Label1所在的父容器控件LoginView1不是显示多数据行的容器控件,那么Label1生成的ClientID 应该是诸如LoginView1_0_Label一、LoginView1_1_Label1等这样的没有ClientIDRowSuffix部分的格式,可是为咱们来看一下生成的HTML代码:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="LoginView1_0_Label1_0">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="LoginView1_1_Label1_1">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="LoginView1_2_Label1_2">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成的Label1的ClientID都带表示递增行号的后缀字符串0、一、2等(此外请注意LoginView不会产生HTML代码),也就是有ClientIDRowSuffix部分。
咱们再将grd_Account的ClientIDRowSuffix属性更改成数据源中的Account Number字段后再来看看生成的HTML代码:
1 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><table cellspacing="0" rules="all" border="1" id="grd_Account" style="height:63px;width:676px;border-collapse:collapse;"> 2 <tr> 3 <th scope="col">Account Number</th> 4 </tr> 5 <tr> 6 <td> 7 <span id="LoginView1_1060_Label1_1060">Logged</span> 8 </td> 9 </tr> 10 <tr> 11 <td> 12 <span id="LoginView1_1200_Label1_1200">Logged</span> 13 </td> 14 </tr> 15 <tr> 16 <td> 17 <span id="LoginView1_1510_Label1_1510">Logged</span> 18 </td> 19 </tr> 20 </table>
能够看到生成的Label1的ClientID也都带ClientIDRowSuffix部分,只不过ClientIDRowSuffix部分如今是数据源中Account Number字段的值。
因而可知在判断Label1是否在显示多数据行的容器控件中时,断定机制进行了穿透,即假若有这么一组嵌套的容器控件:Control_1<-Control_2<-Control_3<-.......<-Control1_n-1<-Control_n,其中Control_n的ClientIDMode设置或继承为Predictable,且其中Control_2到Control1_n-1都不是显示多数据行的容器控件,只有最外层的Control_1是显示多数据行的容器控件,那么在断定最里面的Control_n是否在显示多数据行的容器控件时,参考的是从里到外第一个是显示多数据行的容器控件Control_1(即从里到外只要任意一个容器控件是显示多数据行的容器控件,就认为Control_n是在显示多数据行的容器控件中),而且Control_n的后缀字符串部分参考的也是Control_1的ClientIDRowSuffix属性,从而忽略中间那些不是显示多数据行的容器控件(Control_2到Control1_n-1),因此控件的ClientIDMode属性为Predictable时,就是用这种穿透断定来判断该控件是否在显示多数据行的容器控件中的。