【转】 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交互一般情況下使用<%=控件ID.ClientID%>就OK了,但如果用到母版頁(MasterPage)則要使用UniqueID獲得獲值。(只讀)
?
例如,創建以下 ASP.NET 服務器控件:
<asp:textbox id="TextBox1" runat="server" text="Sample Text" />
ClientID 屬性被設置為 TextBox1,在基于 HTML 的瀏覽器中,其結果元素與以下所示類似:
<input name="TextBox1" type="text" value="Sample Text" id="Text1" />
?
可以使用這些屬性在客戶端腳本中引用服務器控件。通常,必須在客戶端腳本中用完全限定引用來引用控件;如果控件是頁面中 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:
?
假設有子控件:
<asp:TextBox ID = "textboxInfo" runat ="server" Text = "Test Text box" name="haha"></asp:TextBox>
那么我們可以在腳本中這樣寫
var tempt = '<%=textboxInfo.ClientID%>';
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('<% = someControl.ClientID %>');
關于 UniqueID的層次分隔符號,1.x 中為 :(冒號),而 2.0 已實現為 $(美元符),主要原因可能是 javascript 中標識符是允許 $,而不允許 : 的。(當你偷懶的時候,可以在 js 中直接使用表單元素的 name屬性應用該表單元素,而不用 document.getElementsByName 或者 document.getElementById,不推薦:)
ASP.NET 使用的回發機制(簡單版本)是通過一個原型為 __doPostBack(<ControlUniqueID>, <CommandArgs>) 的 javascript 函數
function __doPostBack(eventTarget, eventArgument) {
??? if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
???????? theForm.__EVENTTARGET.value = eventTarget;
???????? theForm.__EVENTARGUMENT.value = eventArgument;
???????? theForm.submit();
???? }
}
此函數的第一個參數 <ControlUniqueID> 對應引起頁面回發控件的客戶端 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_控件名,所以就只??丶?#xff0c;于是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 HTML 4.0 Transitional//EN" >
變成了
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">!
很早以前就稱的HTML的接班人XHTML,現在MS終于要將它扶正了..
這樣在寫HTML代碼時就要注意了,
如:
<font>
??? <div>
??? </font>
??? </div>
是無法在Vs2005中的Design模式中正確顯示的[很明顯的錯誤,但在HTML可以正常顯示].. ,XHTML的語法比HTML嚴格的
多
而關于XHTML和HTML的區別,如果不是非常明白http://www.blueidea.com/tech/site/2004/1911.asp這個文章可以參考一下。
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內嵌到網頁中去.
這樣頁面幾乎所以部分都可以得到控制了
有些人也許會想那<html>和<body>呢
我們先來運行一下面這個代碼.
?? private void Page_Load(object sender, EventArgs e)
??? {
??????? foreach (Control ctl in Page.Controls)
??????? {
??????????? Response.Write(ctl.ToString() + "<BR/>");
??????????? 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">
<html xmlns="http://www.w3.org/1999/xhtml" >
System.Web.UI.LiteralControl
<body>
????
System.Web.UI.LiteralControl
</body>
</html>
所以如果你要對body或<!DOCTYPE..>或<html>進行控制那你就找到這相應的控件以后再進行相應的修改吧。只要對
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("<%=Me.txtTest.ClientID %>" )
來獲取一個控件的真實引用,當然,FindControl等方法也可以寫在<%=...%>中用來綁定服務端數據到客戶端。
?
external JS情況下的解決方案
然而,部分情況下,為了解耦,我們常常把JavaScript單獨寫在.js文件中,再引用到aspx文件中去。這種情況下,.js文件內的代碼不能通過<%=...%>來進行服務端數據的綁定,所以上面的方法是不能用的。
此時簡單點的解決方案就是直接在JavaScript中寫控件的ClientID,但這樣增加了JS文件和ASPX的耦合度,非常不推薦使用。
我常用的方法有兩種,在此拋磚引玉:
?
案例:
Default5.aspx是MasterPage.master 的內容頁,本例中的主要文件。
JScript.js是一個外部的js文件,用來處理JavaScript操作。
Button1是Default5.aspx中的一個<ASP:Button>,用來顯示效果。
Button2是Default5.aspx中的一個<input type=button>,用來觸發JavaScript。
需求:點擊Button2,將Button1上的文本改成“from extended js”
?
方案一:使用內聯JS訪問器
要想在外部JS中獲得ASPX動態生成的ClientID,可以通過在ASPX頁面中添加訪問器的方式來實現,類似OO語言中的屬性:
我們在Default5.aspx中添加如下代碼:作用:①聲明getClientId訪問器,并注冊Button1的ClientID。②引用JScript.js文件
--><script type="text/javascript">
??? function getClientId()
??? {
???? var paraId1 = '<%= Button1.ClientID %>';
???? return {Id1:paraId1};
??? }
</script>
<script type="text/javascript" src="JScript.js"></script>
接下來,我們在JScript.js中,就可以這樣來實現需求:
-->function ChangeText()
{
??? var btn=document.getElementById(getClientId().Id1);
??? btn.value="from extended js";
}
getClientId().Id1 貌似很OO,而且還支持VS2008很蹩腳的JS智能提示,打上“.”之后就可以在提示中選擇Id1了。
如果有多個控件需要注冊,只需將他們注冊到訪問器中即可,下面是一個完整的Demo代碼:
?
></script>//引用外部js
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
??? <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
??? <asp:Button ID="Button1" runat="server" Text="Button" />
??? <input id="Button2" type="button" value="button" οnclick="ChangeText();" />
</asp:Content>
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:
--><script type="text/javascript">
??? var globals = {};
??? globals.controlIdentities = {};
??? globals.controlIdentities.someControl1 = '<%= Button1.ClientID %>';
??? globals.controlIdentities.someControl2 = '<%= TextBox1.ClientID %>';
</script>
<script type="text/javascript" src="JScript.js"></script>
接下來,我們在JScript.js中,就可以這樣來實現需求:
-->function ChangeText()
{
??? var btn=document.getElementById(globals.controlIdentities.someControl1);
??? btn.value="from extended js";
}
globals.controlIdentities.someControl1,同樣,也支持VS2008很蹩腳的JS智能提示,打上“.”之后就可以在提示中選擇someControl1了。下面是一個完整的Demo代碼:
?
></script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
??? <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
??? <asp:Button ID="Button1" runat="server" Text="Button" />
??? <input id="Button2" type="button" value="button" οnclick="ChangeText();" />
</asp:Content>
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文件中,最好還是加上:
-->///<reference path="Default5.aspx"/>
上面的方法是我常用的,今天倉促的總結了一下,希望在此能夠拋磚引玉,謝謝!
?
--------------------------------------------------------------------------
?
ASP.Net中如何使用ClientID
?
ASP.Net 提供了代碼和頁面分離的機制,在大多數情況下,這種機制工作得非常好。但是,如果需要使用客戶端java腳本來做些工作,你就會遇到麻煩了。問題出在你在設計階段為server端控件設置的ID值和頁面運行時控件實際的ID值不一致。例如,新建一個Web site,增加一個 aspx page,在頁面上加入一個text box控件:
<asp:TextBox ID="mytext" Runat=server></asp:TextBox>???
運行這個頁面,從View source中會看到運行時的結果:
<Input name="mytext" type="text" id="mytext" />
這時我們看到設計階段的ID值和運行時控件的ID值是一樣的,沒有問題,這是因為這是一個單純的aspx頁面。如果在頁面中包含一個用戶自定義的web control或使用了master pages (ASP.NET 2.0),情況就不樂觀了。
我們增加一個新的user control名為mycontrol.ascx. 在mycontrol.ascx中加入同樣的text box。再把這個自定義控件加入到一個aspx 頁面, 將此控件的ID設置為myControl. 在瀏覽器中運行這個頁面,得到的html是這樣的:
<Input name="myControl:mytext" type="text" id="myControl_mytext" />
text box控件的設計階段ID= mytext,但運行時得到的ID=myControl_mytext。也就是在原來的ID前面增加了包含text box控件的容器myControl的ID。在使用master pages時,所有的aspx 頁面都是被包含在一個容器中的, 而且還常常會有容器的嵌套。如果在客戶端使用JavaScript去按照ID查找控件就會失敗。解決這個問題可以有多個方法。
最簡單的:
<script language="javascript" type ="text/javascript>
??????? var x=<% Response.Write("'"+myControl.ClientId+"';" ) %>
??????? function doSomething()
??????? {
??????? Var myControl=document.getElementById(x);
??????? }
</script>
這種方法對于一個兩個控件比較適用。不過由于必須在aspx頁面中設置,不能將javascript集中起來管理了。
那么,有沒有可以不進行硬編碼的方法呢?本文提供了一種方法,可以使用ASP.Net現有技術實現,并且適合所有的ASP.Net framework版本。
解決方案
關鍵是創建一個不會被服務器端修改的客戶端控件。在自定義控件上增加一個hidden input,將它設為literal server side control:
<input type=hidden id="ctrlPrefix" name="ctrlPrefix" value='<asp:Literal Runat=server ID=ctrlPrefix></asp:Literal>'>
還要注意,這個hidden input控件需要加入到控件容器里面。因為我們后面要用它來得到控件的ID。在后臺代碼中對Page_Load 事件加入如下處理:
string []elm =ctrlPrefix.ClientID.Split('_');??????????
ctrlPrefix.Text = ctrlPrefix.ClientID.Replace(elm[elm.Length - 1],"");???
我們得到控件的client id,包含了控件的ID加上控件容器的ID作為前綴。第二行代碼將ctrlPrefix.ClientID的后面一段去掉,得到容器的ID前綴,返回值包含了_。編譯后運行這個頁面,結果如下:
<input name="myControl:mytext" type="text" id="myControl_mytext" /><input type=hidden id="ctrlPrefix" name="ctrlPrefix" value='myControl_'>
現在,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();??????????
var??????? objCrtl = document.getElementById(prefix + ctrlName);
?????????? if (objCrtl)???????????????? alert ( "Prefix: " + prefix + " - value: " + objCrtl.value);
?????????? else???????????????? alert("not found!");
}
這個方法顯示textbox控件的值。你會注意到,這里調用了getCtrlPrefix來計算textbox控件的ClientID。 我們可以增加一個按鈕來調用這個方法:
<input type=button value="Read Value" οnclick="javascript:readValue('mytext')">
這個html button會調用readValue。最后,把這個javascript的js文件加入aspx中。
<script language="JavaScript" src="mycontrol.js"></script>
運行這個頁面,在text box中輸入寫數據,然后點擊按鈕,會出現一個消息對話框來顯示ID前綴以及text box中的數據。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jamestaosh/archive/2009/07/22/4370127.aspx
| 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 UniqueID 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) 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 <asp:Label ID="Label1" Text="Label" /> will render as this: <span id="Label1">Label</span> 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("<%= Label1.ClientID%>"); 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:
var control = $find("<%= MyControl1.ClientID %>"); |
轉載于:https://www.cnblogs.com/gossip/archive/2011/11/25/2262648.html
總結
以上是生活随笔為你收集整理的【转】 ID,ClientID和UniqueID的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 德才装饰股票代码
- 下一篇: word打印版面自动缩小的问题解决