在托管代碼或 JavaScript 中,您可以在運行時期間引用 Silverlight 的 Silverlight 對象樹中的 對象。本主題介紹如何在 Silverlight 托管 API 中使用對象樹。
對象樹
對象樹概念描述如何使在運行時在 Silverlight 內(nèi)容中創(chuàng)建和存在的對象彼此相關(guān)。關(guān)系基于對象具 有屬性這一原則,在很多情況下屬性的值是另一個對象,而此對象也具有屬性。對象樹具有分支,因為其 中某些屬性是集合屬性并具有多個對象;并且,對象樹具有根,因為體系結(jié)構(gòu)最終必須引用單個對象,而 該對象是與對象樹之外的概念(例如,瀏覽器宿主或顯示內(nèi)容的 Silverlight 插件)之間的連接點。
盡管在概念上實際只有一個對象樹,但 Silverlight API 不向您公開完整的樹。大量的對象樹結(jié)構(gòu)實 際上是實現(xiàn)詳細信息。而您具有對象特定的屬性,這些屬性影響樹中特定點的子項值并且可能報告父項( 在大多數(shù)情況下,父軸是只讀的,因為您通常是在代碼中或通過 XAML 分析過程從根向上構(gòu)建樹)。例如 ,Panel 具有其 Children 屬性,該屬性設置子對象。FrameworkElement 具有用于報告父項的 Parent。 這兩個 API 都在基類中,因此,它們可用于大量的 Silverlight 對象。
Silverlight 中一個相關(guān)的樹概念是可視化樹。可視化樹概念指的是較大的對象樹在經(jīng)過編輯或篩選 后的表示形式。所應用的篩選器是在可視化樹中只存在具有呈現(xiàn)含義的對象。例如,某個集合類不是可視 化樹的一部分,而可視化樹將集合抽象為一個“子項”概念。然而,如果您將加載的源 XAML 標記視為與 對象樹近似的結(jié)構(gòu),則可視化樹也可以包含并不直接顯示的對象。這是因為,可視化樹也報告作為特定控 件(這些控件來自所應用的控件模板或資源字典)的組成部分的對象??梢暬瘶湓趦?nèi)部用于 Silverlight 呈現(xiàn)過程,但了解一些有關(guān)可視化樹的內(nèi)容對于某些情形通常很重要,例如,在應用模板后編寫或替換控 件模板或在運行時分析控件實例。對于這些情形,Silverlight 提供了 VisualTreeHelper API,它通過 一種方式檢查可視化樹,這種方式比您通過對象特定的父屬性和子屬性來實際實現(xiàn)更為一般化。
可視化樹概念也存在于 WPF 中,它與 Silverlight 的可視化樹概念類似。然而,一個顯著的差異是 WPF 還提供一個附加的篩選器或?qū)ο髽洌ǚQ為“邏輯樹”)的概念。邏輯樹概念與某些屬性系統(tǒng)行為相關(guān) 。Silverlight 不通過幫助器類來公開此邏輯樹。Silverlight 中的確存在某些(但并非所有)相關(guān)的屬 性行為,但由于沒有用于訪問這些行為的幫助器 API,因此,邏輯樹概念在 Silverlight 中將沒有用武 之地,因此本文檔不討論它。缺少邏輯樹而引發(fā)的一個很小的兼容性問題是:FrameworkElement.Parent 屬性行為在 Silverlight 版本 3 中是不同的,它實際上報告可視化樹父項。
對象樹和 XAML 標記
如果您將通過 Silverlight API 訪問的對象樹與 XAML 標記的樹形狀進行比較,它們在節(jié)點方面并不 完全匹配。這是因為 XAML 用于標記,并且在標記定義期間易于使用。例如,XAML 具有屬性元素的概念 ,它提供相關(guān)的指導信息,當您發(fā)現(xiàn)一個元素嵌套在另一個元素內(nèi)時,您可以選擇要設置的屬性。在對象 樹中,這就像一個對象上的某個屬性由另一個對象進行設置一樣。相反,XAML 也具有內(nèi)容屬性的概念, 其中,所設置的屬性在標記中甚至沒有顯式進行命名。XAML 具有的語法可以基于屬性的字符串值創(chuàng)建對 象,也可以針對 XAML 標記中已存在但在其他位置定義的對象提供引用,或者完全位于標記外部。盡管存 在這些很小的不一致,但當您在 XAML 中定義用戶界面時,您將在運行時定義最終 Silverlight 對象樹 的近似結(jié)構(gòu)。
引用對象屬性
無論您通過何種方式從 Silverlight 對象樹中獲取對象引用,都將通過 object.property 表示法( 與 .NET 中 CLR 屬性的核心概念相關(guān))直接公開托管 API 中的屬性。許多 Silverlight 2 屬性的基礎(chǔ) 是依賴項屬性概念。依賴項屬性和屬性系統(tǒng)引入了一些其他可能的語法,用于通過與 object.property 不同的方式訪問屬性,但與附加屬性的情況不同,這些屬性并不常用,因此本主題不討論它們。主題依賴 項屬性概述中詳細討論了依賴項屬性。
對象樹中的附加屬性
Silverlight 支持附加屬性的概念。從對象樹的角度來看,附加屬性是可以附加到樹中任何對象的屬 性,而不考慮該對象的類型(盡管在 Silverlight 實現(xiàn)中,該對象至少必須是依賴項對象)。附加屬性 值存在于對象樹中,但是,如果您使用代碼來訪問它們,則必須使用與 object.property 表示法不同的 語法。
對象樹中的資源和模板
Silverlight 支持一個稱為資源字典的資源概念。資源字典用于指定自身需要大量子屬性設置的屬性值。
ResourceDictionary 最常見的方案是在 XAML 中定義 ResourceDictionary 元素,然后通過 XAML 屬 性 (attribute) 和 StaticResource 標記擴展將已定義的資源用作屬性 (property) 值。對于某些情況 ,可以共享此資源。例如,您可以定義一個 LinearGradientBrush(它在 ResourceDictionary 中包含多 個漸變停止點),然后將其應用于可視化設計中的多個 Brush 屬性(可能在位于不同頁的用戶界面中) 。
模板將按稍微不同的概念運行(無論是在頁級別還是在應用程序級別資源字典中定義,也無論是在 generic.xaml 中還是以內(nèi)聯(lián)方式)。模板自身是一個對象,但模板可能多次應用于可視化樹。在應用后 ,模板中的元素通常使用 TemplateBinding,這樣,就可以應用模板并仍然設置由模板化對象保留的特定 值。有關(guān)模板的基礎(chǔ)概念將在主題通過使用 ControlTemplate 自定義現(xiàn)有控件的外觀中討論。
遍歷對象樹
遍歷對象樹在對象模型中是一種通用的方法。遍歷樹意味著您可以使用針對包含對象引用子對象(通 常,這些是集合)或父關(guān)系的屬性(這通常是在集合內(nèi)完成的,并返回集合自身)。我們可以對此過程進 行粗略的說明:您調(diào)用一連串子屬性和父屬性(或可能調(diào)用幫助器方法)以導航對象樹的各個軸,直到您 檢索到包含您所查找的對象的值。
通常,您應該可以在 XAML 中針對 Silverlight 構(gòu)造您的內(nèi)容,這樣,您就不需要大量查詢樹的結(jié)構(gòu) 。為了避免需要遍歷樹,請在創(chuàng)建元素的 XAML 中對于 x:Name / Name 屬性向這些元素提供一個值。這 就創(chuàng)建了一個直接引用,該引用可用于標記從 XAML 編譯的類中,與遍歷樹相比,這種獲取對象的方法出 錯的可能性要低得多。
此外,如果您通過代碼構(gòu)造函數(shù)而不通過 XAML 加載來創(chuàng)建對象,則您應該能夠構(gòu)造您的代碼,以便 您可以定義私有字段或變量來在運行時保留對象引用(保留在類中,或在應用程序級別存儲為變量)。
然而,在某些情況下,向?qū)ο筇峁┟Q并在范圍中保留對象引用是不可能的,也是不切實際的。一個 此類方案是:您正在添加由用戶提供或通過數(shù)據(jù)綁定提供的動態(tài)內(nèi)容,而您無法預測所添加的項數(shù)或運行 時對象樹的結(jié)構(gòu)。另一個方案是檢查對于某個控件所應用的模板,或控件的某個組成部分。
警告說明警告:
Silverlight 通常支持“設置外觀”概念,也稱為重新設置控件樣式或控件重新模板化。尤其是,如 果您是控件作者且正在編寫控件的支持代碼,則假定特定的樹結(jié)構(gòu)可能很危險。因為大多數(shù)控件支持可設 置的模板(無論您是否已啟用多個特定的擴展點,如子部分樣式),所以,運行時可視化樹可能與通過所 應用的默認模板創(chuàng)建的樹不同。請參見通過使用 ControlTemplate 自定義現(xiàn)有控件的外觀。
用于遍歷“子項”和其他集合的 Try-catch 邏輯
如果您遍歷對象樹的要求涉及到查找某些對象,而這些對象所表示的集合未表示為可視化樹的一部分 ,則您可能需要編寫專用的函數(shù),以便嘗試查找與特定的命名模式或特定類的對象模型相匹配的 API。
向下(遠離根)遍歷對象樹的多個級別通常是可能的,只要您了解所包含的對象將具有集合的點。您 可能必須使用 try/catch 方法或其他等效方法來檢測這一點,即檢查 Children 是否存在以及 Count 是 否為非零值(此處的 Children 和 Count 是占位符,而不是文字 API;根據(jù) .NET 命名原則,Children 和 Count 剛好是這些類型的屬性的公共名稱,但根據(jù)對象及其對象模型,實際屬性可能具有不同的名稱 )。總體 Silverlight 對象模型中的某些集合包含在未命名為 Children 的屬性中。如果您知道您正在 遍歷到某個未命名為 Children 的特定集合屬性,則應在邏輯中說明此情況。
使用 VisualTreeHelper
VisualTreeHelper 是一個可用于遍歷對象樹的實用工具類。(可視化樹的概念已在本主題前面的“對 象樹”一節(jié)中介紹。)
因為您可以在運行時對可視化樹執(zhí)行操作,并且可以遍歷到模板部件,所以這可能是一種可用來檢查 模板組成情況的有用手段。此外,您可以檢查可能通過數(shù)據(jù)綁定填充的子集合,或者您的應用程序代碼可 能無法全部了解運行時對象樹的完整本質(zhì)的子集合。為此,您可以通過 GetChild 并將 GetChildrenCount 用作一個確定因素(確定樹節(jié)點是單個項還是應按計數(shù)進行迭代的“子項”集合)來 遍歷該樹。
遍歷模板內(nèi)容
除VisualTreeHelper 之外,可用來遍歷模板內(nèi)容的另一個方法是 GetTemplateChild。使用 GetTemplateChild 或遍歷模板內(nèi)容通常是必要的,因為 FindName 的行為由名稱范圍概念控制。在這種 情況下,模板內(nèi)容與對象樹的其他部分具有特意不同的名稱范圍,因為模板是共享的,如果不采用單獨的 名稱范圍,則在多次應用模板時會導致名稱沖突。GetTemplateChild 按其模板名稱范圍 x:Name 值查找 對象,同時從應用該模板的特定 Control 的更大對象樹范圍中遍歷。
Silverlight 對象和 HTML DOM
還有另一個對象模型可用于為 HTML 編寫腳本:HTML 文檔對象模型 (DOM)。然而,DOM 不會將 Silverlight 插件加載的內(nèi)容標識為 DOM 的一個完整部分。
新聞熱點
疑難解答
圖片精選