Name与x:Name的关系--转载
小序:
如果想用Google搜包含冒號(hào)的內(nèi)容怎么辦?比如我想搜x:Name這個(gè)字符串……
原來(lái),應(yīng)該是這樣——x::Name
這世道,連搜索也要加轉(zhuǎn)義,全民程序員,要不要人活了?
正文:
從第一天學(xué)習(xí)XAML語(yǔ)言開始,我就一直沒分清為什么對(duì)于一個(gè)XAML標(biāo)簽既可以設(shè)置它的Name又可以設(shè)置它的x:Name。問(wèn)過(guò)一些同事,大家好像對(duì)這種比較孔乙己的問(wèn)題不太感興趣。今天花了些時(shí)間看了看,收獲還挺多的。與大家分享一下。
首先,讓我們剖析一下XAML代碼與C#代碼之間的關(guān)系。
大家都知道,XAML是“用來(lái)設(shè)計(jì)UI”的,設(shè)計(jì)師用XAML設(shè)計(jì)出來(lái)的UI其后臺(tái)代碼(程序邏輯)可以由程序員用C#或者VB去寫——這叫做Code-behind。實(shí)際上,設(shè)計(jì)師用XAML和程序用C#都是在構(gòu)建同一個(gè)類,換句話說(shuō)就是:把一個(gè)類劈成兩半,與UI相關(guān)的那半由設(shè)計(jì)師用XAML寫,與邏輯相關(guān)的那半由程序員用C#寫。
.NET之所以支持這種劈開寫的功能,得益于partial這個(gè)關(guān)鍵字。請(qǐng)大家看這兩段代碼
實(shí)際效果是完全一樣的。只是前者是把UI和邏輯劈開寫,后者是混在一起寫罷了。
劈開的確是劈開了,但讓設(shè)計(jì)師用C#代碼去實(shí)現(xiàn)UI恐怕不現(xiàn)實(shí)——讓Blend直接生成C#不是不可能是事情,只是C#描述UI太不直觀了。于是,微軟更進(jìn)一步,把界面描述語(yǔ)言又向設(shè)計(jì)師方向推進(jìn)了一層,也就是XAML語(yǔ)言。于是,開發(fā)和設(shè)計(jì)的格局就變成了這樣:
有了XAML和將XAML解析為C#/VB的解析器,設(shè)計(jì)師們就能以自己最高的工作效率與程序員們合作開發(fā)軟件了。目前關(guān)于XAML是如何解析成C#/VB的資料非常少。
Name揭秘
下面讓我們把目光集中在XAML->C#的解析上來(lái),看看Name和x:Name的本質(zhì)是什么。
讓我們看一段代碼:
運(yùn)行結(jié)果是:
我用XAML定義了三個(gè)UI元素,其中兩個(gè)TextBox是有Name的。凡是你在XAML代碼里設(shè)置了它的Name,那么在C#代碼里就會(huì)有一個(gè)對(duì)應(yīng)的變量。這可也很好解釋,看看IL程序集就知道了——
不難看出,XAML解析器會(huì)為XAML代碼中設(shè)置了Name的元素聲明同名的引用變量,而且設(shè)置Name的元素則不會(huì)有引用變量生成(不過(guò)這個(gè)元素對(duì)應(yīng)的對(duì)象是存在的,并且是VisualTree/LogicalTree上的結(jié)點(diǎn))。
通過(guò)上面的代碼,我看可以看出,Name的作用有兩個(gè):
1. 告訴XAML解析器為設(shè)置了Name的元素聲明對(duì)應(yīng)的引用變量(本例中是textBox1和textBox2),變量名使用Name的值。
2. 將XAML元素對(duì)應(yīng)的對(duì)象(本例中是兩個(gè)TextBox的實(shí)例)的Name屬性設(shè)置為Name的值。
注意,引用變量一旦聲明之后名字就不能改了,但對(duì)象的Name屬性仍然可以改(示例中我就把由textBox2變量引用著的實(shí)例的Name屬性改成Made_in_China了。)
讓我們?cè)偻谏铧c(diǎn)兒——TextBox的Name屬性是從哪兒繼承來(lái)的呢?查一查MSDN,原來(lái)是從FrameworkElement那兒繼承來(lái)的。這個(gè)Name屬性是非常重要的——如果你想在一棵“樹”上查找叫某個(gè)名字的元素,調(diào)用“樹根”的FindName方法就可以做到了。特別需要注意的是——FindName所使用的參數(shù)是對(duì)象Name屬性的值而不是引用著這個(gè)對(duì)象的變量的名字。如果你的程序里只在XAML里設(shè)置了一次Name,那么引用變量的名字和對(duì)象Name屬性的值恰好一樣。但如果你改變了對(duì)象Name屬性的值,那可就要小心了!請(qǐng)看下面的代碼:
注意,除非我取消對(duì)第17行的注釋,不然,盡管我已經(jīng)把textBox2.Name改成了Made_in_China,但由于這個(gè)新名字還沒有被注冊(cè)(即沒有使用RegisterName方法將Made_in_China和textBox2所引用的對(duì)象關(guān)聯(lián)起來(lái)),我們?nèi)匀徊荒芡ㄟ^(guò)FindName找到它。
我知道這段話挺拗口,不過(guò)有一點(diǎn)你想通過(guò)某種方法查找由DataTemplate自動(dòng)生成的UI元素時(shí),或許應(yīng)該跑來(lái)讀一讀這段繞口令:P
最后再啰嗦一句:為什么這個(gè)Name屬性可以起到在運(yùn)行時(shí)被當(dāng)作查找標(biāo)識(shí)呢?是因?yàn)镕rameworkElement被一個(gè)名為RuntimeNamePropertyAttribute的attribute所修飾。這個(gè)attribute明確指定,FrameworkElement的Name屬性具備了作為查找標(biāo)識(shí)的資格。TextBox等類派生自FrameworkElement,自然也有這個(gè)功能。下面是FrameworkElement類的聲明。
?
[RuntimeNamePropertyAttribute("Name")] [StyleTypedPropertyAttribute(Property?=?"FocusVisualStyle",?StyleTargetType?=?typeof(Control))] [XmlLangPropertyAttribute("Language")] public?class?FrameworkElement?:?UIElement,? ????IFrameworkInputElement,?IInputElement,?ISupportInitialize { ????//... }x:Name揭秘
?
?
x:Name的x加一個(gè)冒號(hào),說(shuō)明它來(lái)自x這個(gè)名稱空間。這個(gè)名稱空間是定義在XAML的根元素上的。也就是這句:
這個(gè)x就是XAML的字頭了。這個(gè)名稱空間的本意就是告訴我們——這個(gè)名稱空間里所裝的元素都與XAML解析有關(guān)。比如,我在代碼里還使用了x:Code,把本來(lái)應(yīng)該呆在C#代碼里的內(nèi)容請(qǐng)到XAML里來(lái)了。
可見,x:Name與Name根本不是一個(gè)層面上的東西——Name是直接與元素和面向?qū)ο缶幊滔嚓P(guān)的東西;x:Name是XAML語(yǔ)言解析層面上的東西。
如果我們把上面代碼中的所有Name都改成x:Name,所有效果都是一樣的。
不知道XAML中標(biāo)有x:的內(nèi)容是不是會(huì)被“預(yù)處理”一下。
Name與x:Name關(guān)系揭秘
不過(guò),如果你的邏輯感比較強(qiáng),你會(huì)發(fā)現(xiàn)這樣一個(gè)問(wèn)題——為一個(gè)XAML元素聲明對(duì)應(yīng)的引用變量,這不是面向?qū)ο缶幊虒用娴臇|西而是XAML解析層的東西。而且,如果Name在語(yǔ)義學(xué)上“恪守本分”的話,它應(yīng)該只去設(shè)置一下對(duì)象的Name屬性值而不去管是不是聲明變量的事兒。
大膽設(shè)想一下,你會(huì)猜到,當(dāng)XAML解析器發(fā)現(xiàn)一個(gè)元素的Name被設(shè)置了,就會(huì)去調(diào)用x:Name的那套機(jī)制。也就是說(shuō),引用變量是在x:Name機(jī)制被調(diào)用的時(shí)候聲明的。同樣,如果你設(shè)置的是元素的x:Name,XAML解析器會(huì)在聲明變量之后再去給實(shí)例的Name屬性設(shè)置值。
這樣的猜想能夠得到證實(shí)嗎?讓我們?cè)贛SDN里搜刮一下。
在x:Name的注釋里,我們能找到這段話:
Under the standard build configuration for a WPF application project that uses XAML, partial classes, and code-behind, the specified x:Name becomes the name of a field that is created in the underlying code when XAML is processed, and that field holds a reference to the object.
而在FrameworkElement.Name屬性的文檔里,又能找到這句話:
This property essentially provides a WPF framework-level convenience property to set the XAML x:Name Attribute.
也就是說(shuō),Name的確會(huì)去調(diào)x:Name那套機(jī)制。為什么這么做?可能是為了寫起來(lái)方便。不過(guò),我真不太喜歡這種攪和在一起的風(fēng)格。我寧可使用Name去給對(duì)象的Name屬性賦值而使用x:Name去聲明變量。
貌似“Under the standard build configuration ”這句話有點(diǎn)玄機(jī)。不知道非standard編譯配置會(huì)有什么樣的效果,怎樣才能自定義編譯配置呢?
不喜歡這種風(fēng)格的原因還在于:Name和x:Name互相調(diào)用會(huì)在某些邏輯下出問(wèn)題,特別是“先有雞還是先有蛋”這種情況下。
關(guān)于在XAML中使用同一個(gè)程序集中的User Control
說(shuō)到“先有雞還是先有蛋”的問(wèn)題,讓我想起了另一個(gè)困擾自己很久的問(wèn)題。請(qǐng)看下面的代碼:
假設(shè)我有這樣一個(gè)project,
現(xiàn)在我想把MyControl用在我的Window1里。如果代碼寫成這樣:
當(dāng)編譯的時(shí)候,會(huì)報(bào)出錯(cuò)誤:
最讓人哭笑不得的原因就是“因?yàn)镸yControl是在同一個(gè)程序集里,你就得使用x:Name而不是Name!”這算什么解釋?跟是不是同一個(gè)程序集有什么關(guān)系?
=====================================
崔維福的補(bǔ)充:
"跟是不是同一個(gè)程序集有什么關(guān)系" 具體來(lái)說(shuō)還是有關(guān)系的。你一定知道Name不能和x:Name同時(shí)用,因?yàn)樵赽uild的時(shí)候他知道這兩個(gè)做了相同的工作,什么工作呢,就是做在“類名.g.cs”,中添加了后臺(tái)代碼,x:Name是Attribute,而Name是DP,編譯器可以挖掘Attribute來(lái)為自己的后臺(tái)添加內(nèi)容,但是不能用Name來(lái)添加,因?yàn)樽约哼€沒有被構(gòu)造完全呢。所以呢就是告訴你,要用x:Name,要不就把這個(gè)contro放到別的project下,它好能把它構(gòu)造出來(lái)!希望我解釋的夠清楚!
作者:
感謝崔先生的批注,您對(duì)技術(shù)精益求精的精神讓我非常景仰,向您學(xué)習(xí)、致敬!
轉(zhuǎn)載于:https://www.cnblogs.com/tianyutingxy/archive/2011/02/23/1962078.html
總結(jié)
以上是生活随笔為你收集整理的Name与x:Name的关系--转载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: jquery 获得鼠标指针 X/Y 值
- 下一篇: jQuery总体架构的理解