技术经验解读:【转】ID,ClientID和UniqueID

简介: 技术经验解读:【转】ID,ClientID和UniqueID

在ASP.NET 的服务器端控件中有三种关于 ID 的属性,即 ID, ClientID 和 UniqueID。


ID 表示控件的服务器端编程的标识符,我们写"服务器端的代码",就要用到这个 ID, 通过这个 ID 可以在服务器端对服务器端控件的属性、方法和时间进行编程访问。(可写)


ClientID 表示由服务器端生成的客户端控件的ID,"经常用于在客户端脚本中访问服务器控件所呈现的 HTML 元素"。一般情况下与服务器端的 ID 相同,有时,不能为控件生成唯一的名称,例如,如果Repeater 空间在它的某个模板中包含一个 Label 控件,则将在客户端生成多个该 Lable 的 HTML 元素, 为防止命名冲突,ASP.NET 为各个服务器控件生成一个唯一的 ClientID ,ClientID 通过将子控件的父控件的 UniqueID 值与控件的 ID 值连接生成,各个部分之间以下划线 连接。(只读)


UniqueID 用于获取服务器控件的唯一的、以分层方式表示的标识符。当将控件放置到重复控件(Repeater、DataList和DataGrid)中时,将可能生成多个服务器端的控件,这就需要区分服务器端的各个控件,以使它们的 ID 属性不冲突。UniqueID 通过将子控件的父控件的 UniqueID 值与控件的 ID 值连接生成,各个部分之间以IdSeparator 属性指定的字符连接。默认情况下, IdSeparator 属性为冒号字符 (:)。此属性为在 .Net Framework2.0种新增加。js与aps.net交互一般情况下使用就OK了,但如果用到母版页(MasterPage)则要使用UniqueID获得获值。(只读)


例如,创建以下 ASP.NET 服务器控件:


ClientID 属性被设置为 TextBox1,在基于 HTML 的浏览器中,其结果元素与以下所示类似:


可以使用这些属性在客户端脚本中引用服务器控件。通常,必须在客户端脚本中用完全限定引用来引用控件;如果控件是页面中 form 元素的子控件,则一般使用document.forms【0】.TextBox1.value = "New value"在客户端脚本中引用控件。


有些控件将子控件呈现在页面中。这些控件中包括数据列表控件(如GridView、DetailsView、FormView、DataList 和 Repeater 控件)、用户控件和 Web 部件控件。可以看到,在这些情况下,子控件可能不具有唯一的 ID,这可能是因为子控件是在某个模板中定义的,该模板会为每个数据行(数据列表控件)生成新的控件实例,也可能是因为可以从外部源(用户控件和 Web 部件控件)将父控件添加到页面中对于每个子控件:控件的 UniqueID 被呈现为 name。控件的 ClientID 被呈现为 id 属性。


ClientID 和 UniqueID 属性都基于原始的 ID 属性,并用足够的信息进行了修改,以保证页面中结果的唯一性。ClientID的值可在客户端脚本中引用。如果在浏览器中显示一个具有命名容器的页面,则可以查看该页面的源文件,从中找到唯一的 ID,这些 ID 作为命名容器子控件的 name 属性和 id 属性生成。但是,建议不要依赖于直接引用在浏览器中看到的 ID。因为用于生成子控件唯一ID 的公式可能会发生变化,应当获取子控件的 ClientID 属性值,并用该值来引用该子控件。例如,您可能会在页面中动态创建客户端脚本。如果客户端脚本引用一个子控件,则应获取该子控件的 ClientID 属性,并将其嵌入到动态脚本中。


例2:


假设有子控件:


那么我们可以在脚本中这样写


var tempt = '';


var controlname = document.getElementById(tempt).name;


var controlid = document.getElementById(tempt).id;


  还有一个问题我们需要注意:在使用UniqueID和ClientID的时候要小心点,千万不要“迫不及待”地使用了这些属性,在运行的过程中可能会碰到一些让人头疼的问题.


注意


除了用来分隔 ID 值的是下划线字符而不是 IdSeparator 属性指定的字符以外,为控件生成的 ClientID 值与 UniqueID 值相同。默认情况下,IdSeparator 属性设置为冒号字符 (:)。由于 ClientID 值不包含冒号字符,因此,它可以用于不支持包含冒号的 ID 的 ECMAScript。ClientID 值经常用于以编程方式访问为客户端脚本中的控件呈现的 HTML 元素。有关详细信息,请参见 ASP.NET 网页中的客户端脚本。


总结:


ID,用于server端编程引用控件,没有对应的client值,即不呈现到html中。


UniqueID,


asp.net引擎按控件树层次生成的分层形式限定的标志符,连接符默认为 $ (美元符号)【注:MSDN说默认为 : (冒号),实际是 $ ,可能文档有误吧】,此连接符在asp.net 2.0 中由属性 IdSeparator 指定,在client中呈现为html元素的name属性


此属性主要用来提交(PostBack)客户端数据,如Request.Form【someControl.UnqiueID】


ClientID,


由父控件的UnqiueID连接本身ID而成,但是连接符不一样,默认为 (下划线),此连接符在asp.net 2.0 中由属性 ClientIDSeparator 指定,在client中呈现为html元素的id属性,此属性主要在客户端教本中使用,如 var o = document.getElementById('');


关于 UniqueID的层次分隔符号,1.x 中为 :(冒号),而 2.0 已实现为 $(美元符),主要原因可能是 javascript 中标识符是允许 $,而不允许 : 的。(当你偷懒的时候,可以在 js 中直接使用表单元素的 name属性应用该表单元素,而不用 document.getElementsByName 或者 document.getElementById,不推荐:)


ASP.NET 使用的回发机制(简单版本)是通过一个原型为 doPostBack(, ) 的 javascript 函数


function doPostBack(eventTarget, eventArgument) {


if (!theForm.onsubmit || (theForm.onsubmit() != false)) {


theForm.EVENTTARGET.value = eventTarget;


theForm.EVENTARGUMENT.value = eventArgument;


theForm.submit();


}


}


此函数的第一个参数 对应引起页面回发控件的客户端 name 属性/服务端 UniqueID 属性,当用户引发一个事件,如点击按钮,选择列表框的某一项,首先通过 doPostBack 函数将此值存在隐藏域中,然后提交页面。


在服务器端,ASP.NET 引擎通过 HttpRequest.HttpMethod 确定请求是否为 post 方式,若是,则检索HttpRequest.Request.Form【"__EVENTTARGET'】, 获取引发回发的控件唯一标识符,并在页面控件集合层次中查找,若找到此控件,则将在适当阶段引发服务器端事件。


另补充控件变化规律如下:


控件名字发生变化是因为 INamingContainer这个接口。这个接口没有任何方法,仅只作为一个标记。ASP.NET维护控件name和id生成的规律是:NamingContainer爷爷$NamingContainer爸爸$该控件的ID。id则一般将$换为""。


你把控件直接放到form下,它头顶唯一一个NamingContainer是Page,但是这个是特殊的逻辑,不会生成Page_控件名,所以就只剩控件名了,于是ID看起来没有变化。


当你把控件放到Repeater中时,Repeater自己被INamingContainer标记,同时,每一次循环,它会把模板内的控件重新生成一遍,同时生成一个RepeaterItem, 把这些根据模板生成的控件加入RepeaterItem的子控件。这个RepeaterItem也是一个NamingContainer. 于是控件中就会带有:


RepeaterID(Data)RepeaterItemID(ctl + 号码)控件ID.


不过非runat=server控件因为不由ASP.NET维护, 不会发生变化. UserControl.ascx由于其基类也是一个NamingContainer, 所以如果你把控件放入.ascx, 然后在页面上引用, 则前面又会多一层UserControl的ID.


通过controls集合访问服务器控件:


在VS2005中新建一个.aspx文件,打开HTML页会发现一个原先的声明从


变成了


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">!


很早以前就称的HTML的接班人XHTML,现在MS终于要将它扶正了..


这样在写HTML代码时就要注意了,


如:


是无法在Vs2005中的Design模式中正确显示的【很明显的错误,但在HTML可以正常显示】.. ,XHTML的语法比HTML严格的



而关于XHTML和HTML的区别,如果不是非常明白这个文章可以参考一下。


Form


Form新添加了几个功能比较有用的是defaultbutton、defaultfocus。从字面的意思大家就可以理解了以前在ASP.NET中让人头痛的默认提交表单按钮和设置焦点在ASP.NET 2.0已经提供了,不用象以前那样自己写javascript来控制了


关于焦点在也可以代码中通过 this.SetFocus()来设置了,看得出来ASP.NET2.0是设计是多么的细致。


Header


在代码中可能通过


this.Header.Metadata.Add("taye", "value");


this.Header.Title = "value";


this.Header.LinkedStyleSheets.Add("style.css");


来控制Title,Meta,Style等【好象LinkedStyleSheets只能是text/css?】


this.Header.StyleSheet.RegisterStyle()


方法将一个style内嵌到网页中去.


这样页面几乎所以部分都可以得到控制了


有些人也许会想那和呢


我们先来运行一下面这个代码.


private void Page_Load(object sender, EventArgs e)


{


foreach (Control ctl in Page.Controls)


{


Response.Write(ctl.ToString() + "


");


LiteralControl lc = ctl as LiteralControl;


if (lc != null)


{


Response.Write(lc.Text);


}


}


}


你将会看到一个正常页的有如下五个控件


System.Web.UI.LiteralControl


System.Web.UI.HtmlControls.HtmlHead


System.Web.UI.LiteralControl


System.Web.UI.HtmlControls.HtmlForm


System.Web.UI.LiteralControl


而三个LiteralControl的控件的内容分别为


System.Web.UI.LiteralControl


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">



System.Web.UI.LiteralControl


System.Web.UI.LiteralControl


所以如果你要对body或或进行控制那你就找到这相应的控件以后再进行相应的修改吧。只要对


LiteralControl.Text进行修改就可以.


--------------------------------------------------------------------------


从外部的js文件中获取ASPX页面的控件ClientID


前言


当使用MasterPage、UserControl等容器时,为了避免控件的重复命名,asp.net会自动将容器中的控件生成一个ClientID(Control Tree中的可生成,否则不会生成)。


例如:ContentPlaceHolder1中的Button1默认情况下会生“ctl00_ContentPlaceHolder1_Button1”的ClientID。我们在Render出来的mark up中看到的也是这些ClientID。所以,当我们使用JavaScript对控件元素进行操作的时候,必须使用ClientID来对控件进行查找。


Inline情况下的解决方案


如果JavaScript代码写在.aspx文件中时,也就是Inline Script时。在页面生成的时候,我们能够通过绑定机制将控件的ClientID绑定到页面Mark up中,故可使用:


-->document.getElementById("" )


来获取一个控件的真实引用,当然,FindControl等方法也可以写在中用来绑定服务端数据到客户端。


external JS情况下的解决方案


然而,部分情况下,为了解耦,我们常常把JavaScript单独写在.js文件中,再引用到aspx文件中去。这种情况下,.js文件内的代码不能通过来进行服务端数据的绑定,所以上面的方法是不能用的。


此时简单点的解决方案就是直接在JavaScript中写控件的ClientID,但这样增加了JS文件和ASPX的耦合度,非常不推荐使用。


我常用的方法有两种,在此抛砖引玉:


案例:


Default5.aspx是MasterPage.master 的内容页,本例中的主要文件。


JScript.js是一个外部的js文件,用来处理JavaScript操作。


Button1是Default5.aspx中的一个,用来显示效果。


Button2是Default5.aspx中的一个,用来触发JavaScript。


需求:点击Button2,将Button1上的文本改成“from extended js”


方案一:使用内联JS访问器


要想在外部JS中获得ASPX动态生成的ClientID,可以通过在ASPX页面中添加访问器的方式来实现,类似OO语言中的属性:


我们在Default5.aspx中添加如下代码:作用:①声明getClientId访问器,并注册Button1的ClientID。②引用JScript.js文件


-->


function getClientId()


{


var paraId1 = '';


return {Id1:paraId1};


}


接下来,我们在JScript.js中,就可以这样来实现需求:


-->function ChangeText()


{


var btn=document.getElementById(getClientId().Id1);


btn.value="from extended js";


}


getClientId().Id1 貌似很OO,而且还支持VS2008很蹩脚的JS智能提示,打上“.”之后就可以在提示中选择Id1了。


如果有多个控件需要注册,只需将他们注册到访问器中即可,下面是一个完整的Demo代码:



function ChangeText()


{


var btn=document.getElementById(getClientId().Id1);


btn.value="from extended js";


var btn=document.getElementById(getClientId().Id2);


btn.value="from extended js";


}


方案二:使用JS全局变量


还有一种方法也比较OO,就是使用JS全局变量,同样,也需要在Default5.aspx中添加一段JS代码,作为全局变量,来提供ClientID:


-->


var globals = {};


globals.controlIdentities = {};


globals.controlIdentities.someControl1 = '';


globals.controlIdentities.someControl2 = '';


接下来,我们在JScript.js中,就可以这样来实现需求:


-->function ChangeText()


{


var btn=document.getElementById(globals.controlIdentities.someControl1);


btn.value="from extended js";


}


globals.controlIdentities.someControl1,同样,也支持VS2008很蹩脚的JS智能提示,打上“.”之后就可以在提示中选择someControl1了。下面是一个完整的Demo代码:



function ChangeText()


{


var btn=document.getElementById(globals.controlIdentities.someControl1);


btn.value="from extended js";


var txt=document.getElementById(globals.controlIdentities.someControl2);


btn.value="from extended js";


}


结束语:


在上面两种方法中,也没有真正的实现aspx和js的完全解耦,所以,在js文件中,最好还是加上:


-->///


上面的方法是我常用的,今天仓促的总结了一下,希望在此能够抛砖引玉,谢谢!


--------------------------------------------------------------------------


ASP.Net中如何使用ClientID


ASP.Net 提供了代码和页面分离的机制,在大多数情况下,这种机制工作得非常好。但是,如果需要使用客户端java脚本来做些工作,你就会遇到麻烦了。问题出在你在设计阶段为server端控件设置的ID值和页面运行时控件实际的ID值不一致。例如,新建一个Web site,增加一个 aspx page,在页面上加入一个text box控件:


运行这个页面,从View source中会看到运行时的结果:


这时我们看到设计阶段的ID值和运行时控件的ID值是一样的,没有问题,这是因为这是一个单纯的aspx页面。如果在页面中包含一个用户自定义的web control或使用了master pages (ASP.NET 2.0),情况就不乐观了。


我们增加一个新的user control名为mycontrol.ascx. 在mycontrol.ascx中加入同样的text box。再把这个自定义控件加入到一个aspx 页面, 将此控件的ID设置为myControl. 在浏览器中运行这个页面,得到的html是这样的:


text box控件的设计阶段ID= mytext,但运行时得到的ID=myControl_mytext。也就是在原来的ID前面增加了包含text box控件的容器myControl的ID。在使用master pages时,所有的aspx 页面都是被包含在一个容器中的, 而且还常常会有容器的嵌套。如果在客户端使用JavaScript去按照ID查找控件就会失败。解决这个问题可以有多个方法。


最简单的:


var x=


function doSomething()


{


Var myControl=document.getElementById(x);


}


这种方法对于一个两个控件比较适用。不过由于必须在aspx页面中设置,不能将javascript集中起来管理了。


那么,有没有可以不进行硬编码的方法呢?本文提供了一种方法,可以使用ASP.Net现有技术实现,并且适合所有的ASP.Net framework版本。


解决方案


关键是创建一个不会被服务器端修改的客户端控件。在自定义控件上增加一个hidden input,将它设为literal server side control:



还要注意,这个hidden input控件需要加入到控件容器里面。因为我们后面要用它来得到控件的ID。在后台代码中对PageLoad 事件加入如下处理:


string 【】elm =ctrlPrefix.ClientID.Split('');


ctrlPrefix.Text = ctrlPrefix.ClientID.Replace(elm【elm.Length - 1】,"");


我们得到控件的client id,包含了控件的ID加上控件容器的ID作为前缀。第二行代码将ctrlPrefix.ClientID的后面一段去掉,得到容器的ID前缀,返回值包含了_。编译后运行这个页面,结果如下:


现在,hidden input中已经保存了容器的ID前缀。下面,我们用JavaScript来利用hidden input处理控件查找。


增加一个新的方法getCrtlPrefix()


//returns the container prefix as all controls have that on their ids


function getCrtlPrefix()


{


var prefix;


var objCrtlPrefix = document.getElementById("ctrlPrefix");


if (objCrtlPrefix)


prefix = objCrtlPrefix.value;


return prefix;


}


这个方法得到hidden input的值并返回,这样我们就得到了ID的前缀。第二个方法用来查询空间


function readValue(ctrlName)


{


var prefix = getCrtlPrefix(); //代码效果参考:http://hnjlyzjd.com/xl/wz_24381.html


var objCrtl = document.getElementById(prefix + ctrlName);


if (objCrtl) alert ( "Prefix: " + prefix + " - value: " + objCrtl.value);


else alert("not found!");


}


这个方法显示textbox控件的值。你会注意到,这里调用了getCtrlPrefix来计算textbox控件的ClientID。 我们可以增加一个按钮来调用这个方法:


这个html button会调用readValue。最后,把这个javascript的js文件加入aspx中。


运行这个页面,在text box中输入写数据,然后点击按钮,会出现一个消息对话框来显示ID前缀以及text box中的数据。


本文来自CSDN博客,转载请标明出处:


The difference between ID, ClientID and UniqueID


I this post I will try to explain the difference between those three commonly used properties. Each property is described in a separate section. Attached you can find a sample web site as well as two screenshots visually depicting the difference between the ID, ClientID and UniqueID properties.


ID


The ID property is used to assign an identifier to an ASP.NET server control which can be later used to access that control. You can use either the field generated in the codebehind or pass the value of the ID property to the FindControl method. There is a catch though - the ID property is unique only within the current NamingContainer (page, user control, control with item template etc). If a server control is defined inside the item template of some other control (Repeater, DataGrid) or user control, its ID property is no longer unique. For example, you can add some user control twice in the same page. Any child controls of that user control will have the same ID. Also the ASP.NET page parser won't generate a codebehind field corresponding to the control ID in case the control is defined inside a template. This is the reason you cannot easily find a specific control when it is part of a template - you need to use the FindControl method of its container control instead. As a side note, setting the ID property is not mandatory. If you don't set it the ASP.NET Runtime will generate one for you in the form of "_ctl0", "_ctl1", etc.


UniqueID


The UniqueID property is the page-wide unique identifier of an ASP.NET server control. Its uniqueness is guaranteed by prefixing the ID of a server control with the ID of its NamingContainer. If the NamingContainer is the Page the UniqueID will remain the same as the ID.


For example if a Label with ID="Label1" is defined in a user control with ID = "UserControl1" the UniqueID of the Label will be "UserControl1$Label1". Adding another instance of the same user control (with ID = "UserControl2") will make the UniqueID of its child label to be "UserControl2$Label1".


The UniqueID property is also used to provide value for the HTML "name" attribute of input fields (checkboxes, dropdown lists, and hidden fields). UniqueID also plays major role in postbacks. The UniqueID property of a server control, which supports postbacks, provides data for the EVENTTARGET hidden field. The ASP.NET Runtime then uses the EVENTTARGET field to find the control which triggered the postback and then calls its RaisePostBackEvent method. Here is some code which illustrates the idea:


IPostBackEventHandler postBackInitiator =


Page.FindControl(Request.Form【"EVENTTARGET") As IPostBackEventHandler;


if (postBackInitiator != null)


postBackInitiator.RaisePostBackEvent(Request.Form【"_EVENTARGUMENT"】);


You can use the UniqueID property to find any control no matter how deep it is nested in the control hierarchy. Just pass its value to the FindControl method of the Page.


ClientID


The ClientID property is quite similar to the UniqueID. It is generated following the same rules (the ID of the control prefixed by the ID of its NamingContainer). The only difference is the separator - for the ClientID it is the "" (underscore) symbol.


The ClientID property is globally unique among all controls defined in an ASP.NET page. You may ask why we need two different globally unique properties. The answer is that ClientID serves a different purpose than UniqueID. In most server controls the ClientID property provides the value for the HTML "id" attribute of the HTML tag of that server control. For example this:


will render as this:


Label


That's why you often use the following JavaScript statement to access the DOM element corresponding to some ASP.NET server control:


var label = document.getElementById("");


which in turn renders as:


var label = document.getElementById("Label1");


It is worth mentioning that the values of the ID, UniqueID and ClientID will be the same if the control is defined in the master page (or the page). This however can often lead to unexpected errors. If the ID of the control is hardcoded inside the JavaScript statement (e.g. "Label1") this code will only work provided the control is defined in the Page or master page. Moving the control and the JavaScript code into a userc control with ID "UserControl1" will fail at runtime because the control will now render as:


Label


That's why you should prefer using the "" syntax to get the client-side id of server controls.


Additionaly the ClientID is used in ASP.NET Ajax as the unique identifier of client-side controls. Thus the following JavaScript statement is commonly used:


var control = $find("");

相关文章
|
10月前
企业微信开发之获取media_id的值
企业微信开发之获取media_id的值
246 0
|
安全 索引 算法
分布式唯一ID系列(2)——UUID适合做分布式ID吗
UUID的生成策略: UUID的方式能生成一串唯一随机32位长度数据,它是无序的一串数据,按照开放软件基金会(OSF)制定的标准计算,UUID的生成用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
5528 0
|
26天前
|
机器学习/深度学习 数据采集 人工智能
人工智能平台PAI产品使用合集之如何配置user和item节点
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
9月前
|
数据可视化 机器人
获取机器人id
获取机器人id
23 3
|
11月前
|
SQL 数据采集 NoSQL
One ID中的核心技术ID-Mapping究竟是怎么实现的?by彭文华
One ID中的核心技术ID-Mapping究竟是怎么实现的?by彭文华
|
9月前
|
iOS开发
id的本质
id的本质
37 1
|
9月前
|
Web App开发 缓存 前端开发
回答朋友提问:Fiori UI 中如何知道当前系统 Client ID (一)
回答朋友提问:Fiori UI 中如何知道当前系统 Client ID (一)
|
11月前
|
SQL 数据采集 NoSQL
One ID中的核心技术ID-Mapping究竟是怎么实现的?
One ID中的核心技术ID-Mapping究竟是怎么实现的?
|
11月前
|
存储 缓存 算法
分布式id居然还能这么搞
分布式id居然还能这么搞
67 0
|
消息中间件 JavaScript 算法
ULID - 一种比UUID更好的方案
ULID - 一种比UUID更好的方案