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