亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

WPF中NameScope的查找規則詳解

2019-10-29 19:58:33
字體:
來源:轉載
供稿:網友

前言

我們在 WPF 中使用綁定時可以使用 ElementName=Foo 這樣的寫法,并且還能夠真的在運行時找到這個名稱對應的對象,是因為 WPF 中提供了名稱范圍概念。

實現 INameScope 接口可以定義一個名稱范圍。無論你使用 Name 屬性還是使用 x:Name 特性都可以在一個名稱范圍內指定某個元素的名稱。綁定時就在此名稱范圍內查找,于是可以找到你需要的對象。

XAML中的NameScope

首先來講講WPF的名稱管理機制NameScope,也即是名稱范圍。名稱范圍主要提供了兩種功能:記錄XAML名稱與界面元素實例之間的關聯關系;防止名稱沖突。可以說,第二種功能是第一種功能實現時所產生的副作用。而在XAML中引用某個名稱時,WPF會自動使用相應的NameScope執行對名稱的查找。

那么,WPF的名稱范圍是如何在XAML等程序組成中起作用的呢?如果一個元素在XAML中使用x:Name或Name屬性設置了名稱,那么WPF會為該屬性設置執行一些額外的執行邏輯,如在對應的cs文件中自動生成具有相同名稱的成員,并將它們注冊到相應的名稱范圍中。如果在該范圍中多次使用了相同的名稱,那么WPF會拋出一個異常。在XAML中對某個元素進行引用的時候,WPF會從該NameScope中尋找該名稱所對應的界面元素以進行操作。

當然,用戶并不需要顯式地對名稱范圍進行處理。默認情況下,WPF會使用一定的機制保證該文件中的各個界面元素可以擁有合適的名稱范圍。在XAML中常常作為根元素的Page類及Window類都提供了對名稱范圍的支持。如果XAML中的根元素并不是這兩個類型,那么XAML處理器會在處理過程中為該文件隱式地添加一個Page元素作為新的根元素。通過這種方法,WPF可以保證XAML文件中對x:Name以及Name的使用可以將名稱正確地注冊進相應的名稱范圍中。

本文將介紹 WPF 中 NameScope 的查找規則。(額外的,資源 / 資源字典的查找方式與 NameScope 的方式是一樣的,所以本文分析過程同樣使用與資源的查找。)

INameScope

WPF 的 INameScope 接口只用來管理一個范圍之內的名稱。它包含下面三個方法:

public interface INameScope{ object FindName(string name); void RegisterName(string name, object scopedElement); void UnregisterName(string name);}

它的主要實現是 NameScope,包含了更多功能;而上面的接口是其本2222質功能。

不過,NameScope 的實現帶來了一個重要的依賴項屬性 —— NameScope。下面是此屬性的代碼(經過簡化):

public static readonly DependencyProperty NameScopeProperty = DependencyProperty.RegisterAttached("NameScope", typeof(INameScope), typeof(NameScope));public static void SetNameScope(DependencyObject dependencyObject, INameScope value){ if (dependencyObject == null) throw new ArgumentNullException(nameof(dependencyObject)); dependencyObject.SetValue(NameScopeProperty, value);}public static INameScope GetNameScope(DependencyObject dependencyObject){ if (dependencyObject == null) throw new ArgumentNullException(nameof(dependencyObject)); return ((INameScope)dependencyObject.GetValue(NameScopeProperty));}

同樣實現了此接口的還有 TemplateNameScope,此 NameScope 會被 FrameworkTemplate / FrameworkElementFactory / BamlRecordReader 設置到以上依賴屬性中。于是我們可以在模板范圍內找到某個特定名稱對應的元素。

除此之外,NameScope 的設置由 XAML 解析器在 WPF 項目編譯的時候自動生成。

NameScope 的名稱注冊規則

如果你沒有在代碼中顯式去調用 RegisterName 這樣的方法,那么 NameScope 的創建以及名稱的注冊都由 XAML 解析器來完成。

XAML 解析器(BamlRecordReader)注冊名字的時候并沒有去爬可視化樹什么的,只是單純在解析 XAML 的時候去調用代碼注冊這個名字而已。注冊由一個 Stack 來完成,NameScopeStack。

設想以下這個例子(來自于 .NET Framework 代碼中的注釋):

<Window x:Name="myWindow"> ... <Style x:Name="myStyle"> ... <SolidColorBrush x:Name="myBrush"> </SolidColorBrush> </Style></Window>

每當 XAML 解析器解析一層的時候,就會給 NameScopeStack 入棧,于是 Window 首先創建 NameScope 入棧。隨后解析到 Style 時又加一個 NameScope 入棧,其他元素解析時不會創建 NameScope(包括 XAML 中的頂層元素 UserControl 等)。

這時,myWindow 會被注冊到 Window 一層的 NameScope 中,myStyle 也會注冊到 Window 一層的 NameScope 中;而 myBrush 則會注冊到 Style 那一層的 NameScope 中。

Window 的 NameScope

  • myWindow
  • myStyle

Style 的 NameScope

  • myBrush

NameScope 的名稱查找規則

在本文一開始貼出 NameScope 依賴項屬性的時候,你應該注意到這只是一個普通的屬性,并沒有使用到什么可以用可視化樹繼承這樣的高級元數據。事實上也不應該有這樣的高級元數據,因為 NameScope 的抽象級別低于可視化樹或者邏輯樹。

但是,實際上 NameScope 的查找卻是依賴于邏輯樹的 —— 這是 FrameworkElement 的功能:

internal static INameScope FindScope(DependencyObject d, out DependencyObject scopeOwner){ while (d != null) {  INameScope nameScope = NameScope.NameScopeFromObject(d);  if (nameScope != null)  {   scopeOwner = d;   return nameScope;  }  DependencyObject parent = LogicalTreeHelper.GetParent(d);  d = (parent != null) ? parent : Helper.FindMentor(d.InheritanceContext); } scopeOwner = null; return null;}

非常明顯,FindScope 是期望使用邏輯樹來查找名稱范圍的。

不過值得注意的是,當一個元素沒有邏輯父級的時候,會試圖使用 Helper.FindMentor 來查找另一個對象。那這是什么方法,又試圖尋找什么對象呢?

Mentor 是名詞,意為 “導師,指導”。于是我們需要閱讀以下 Helper.FindMentor 方法的實現來了解其意圖:

提示:以下注釋中的 FE 代表 FrameworkElement,而 FCE 代表 FrameworkContentElement。

/// <summary>///  This method finds the mentor by looking up the InheritanceContext///  links starting from the given node until it finds an FE/FCE. This///  mentor will be used to do a FindResource call while evaluating this///  expression./// </summary>/// <remarks>///  This method is invoked by the ResourceReferenceExpression///  and BindingExpression/// </remarks>internal static DependencyObject FindMentor(DependencyObject d){ // Find the nearest FE/FCE InheritanceContext while (d != null) {  FrameworkElement fe;  FrameworkContentElement fce;  Helper.DowncastToFEorFCE(d, out fe, out fce, false);  if (fe != null)  {   return fe;  }  else if (fce != null)  {   return fce;  }  else  {   d = d.InheritanceContext;  } } return null;}

具體來說,是不斷查找 InheritanceContext,如果找到了 FrameworkElement 或者 FrameworkContentElement,那么就返回這個 FE 或者 FCE;如果到最終也沒有找到,則返回 null。

這是個 virtual 屬性,基類 DependencyObject 中只返回 null,而子類重寫它時,返回父級。Freezable, FrameworkElement, FrameworkContentElement 等重寫了這個屬性。

對于 FrameworkElement,重寫時只是單純的返回了一個內部管理的字段而已:

internal override DependencyObject InheritanceContext{ get { return InheritanceContextField.GetValue(this); }}

此字段在調用 DependencyObject.AddInheritanceContext 的時候會賦值。而對于可視化樹或邏輯樹的建立,此方法不會被調用,所以此屬性并不會對可視化樹或邏輯樹有影響。但是,Freezable, InputBinding, Visual3D, GridViewColumn, ViewBase, CollectionViewSource, ResourceDictionary, TriggerAction, TriggerBase 等會在屬性賦值的時候調用此方法。于是我們能夠在以上這些屬性的設置中找到名稱。

特別說明,只有那些重寫了 InheritanceContext 的類型才會在查找名稱的時候找得到 NameScope;只有以上這些調用了 DependencyObject.AddInheritanceContext 方法的屬性才會在賦值是能夠找得到 NameScope。

所以,我另一篇文章中所說的 ContextMenu 是找不到對應的 NameScope 的。WPF 的 ElementName 在 ContextMenu 中無法綁定成功?試試使用 x:Reference!。此文中 ContextMenu 找到的 NameScope 是 null。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精自产拍久久久久久| 亚洲欧美日韩综合| 色综合视频一区中文字幕| 欧美一级黄色网| 91色在线视频| 国产日韩欧美黄色| 久久久999精品视频| 国产脚交av在线一区二区| 亚洲一区二区三区成人在线视频精品| 高清一区二区三区四区五区| 亚洲夜晚福利在线观看| 色噜噜国产精品视频一区二区| 在线日韩精品视频| 国产精品天天狠天天看| 国产精品99久久久久久久久久久久| 欧美小视频在线观看| 日av在线播放中文不卡| 亚洲美女在线视频| 91视频九色网站| 国产区亚洲区欧美区| 91九色综合久久| www.日韩系列| 91精品视频在线| 成人久久18免费网站图片| 国产精品久久久一区| 久久福利视频导航| 亚洲最大成人网色| 91精品国产综合久久香蕉最新版| 欧美激情国产日韩精品一区18| 国产视频精品xxxx| 久久亚洲综合国产精品99麻豆精品福利| 亚洲成人av在线| 国产精品久久二区| 日韩av一区二区在线观看| 97视频在线观看亚洲| 奇米一区二区三区四区久久| 欧美日韩在线看| 69**夜色精品国产69乱| 欧美亚洲伦理www| 欧美大片免费观看在线观看网站推荐| 久久天天躁日日躁| 日韩在线观看免费全集电视剧网站| 91高潮在线观看| 91免费版网站入口| 国产精品视频xxx| 国产精品无码专区在线观看| 成人激情视频在线| 黑人巨大精品欧美一区二区免费| 亚洲人成网站在线播| 4444欧美成人kkkk| 日韩欧美精品网址| 亚洲人成啪啪网站| 国产精品美女免费视频| 国产亚洲综合久久| 欧美性高潮在线| 亚洲欧美日韩国产精品| 亚洲电影av在线| 久久免费成人精品视频| 精品久久久久久久久久久| 在线看片第一页欧美| 欧美性猛交丰臀xxxxx网站| 亚洲激情在线观看| 亚洲天堂第二页| 精品国产乱码久久久久久天美| 日韩女优在线播放| 亚洲成人精品久久| 日韩亚洲一区二区| 亚洲第一综合天堂另类专| 北条麻妃99精品青青久久| 日韩欧美aⅴ综合网站发布| 欧美性猛交xxxx乱大交蜜桃| 欧美在线免费视频| 中文字幕久久久| 成人中文字幕在线观看| 欧美在线亚洲一区| 日韩av手机在线观看| 91国在线精品国内播放| 96pao国产成视频永久免费| 97视频在线观看视频免费视频| 欧美亚洲视频在线观看| 性色av一区二区三区在线观看| 黄色精品一区二区| 欧美黄色片在线观看| 国产在线观看精品一区二区三区| 免费99精品国产自在在线| 欧美精品一区二区三区国产精品| 91夜夜揉人人捏人人添红杏| 亚洲综合日韩中文字幕v在线| 人人澡人人澡人人看欧美| 国模叶桐国产精品一区| 国产精品视频精品| 91久久久久久国产精品| 亚洲美女在线看| 最新国产精品拍自在线播放| 中文字幕日韩在线播放| 亚洲一级黄色片| 18久久久久久| 欧美午夜激情小视频| 国产精品一区二区三区久久久| 欧美日韩亚洲一区二区| 91精品国产91久久久久久吃药| 97国产精品久久| 成人免费视频网址| 中文在线不卡视频| 在线激情影院一区| 欧美丰满少妇xxxxx做受| 2019亚洲男人天堂| 亚洲精品乱码久久久久久金桔影视| 亚洲精品视频网上网址在线观看| 欧美高清在线播放| 日韩电影大片中文字幕| 伊人久久久久久久久久久| 亚洲视频电影图片偷拍一区| 日韩精品极品视频免费观看| 亚洲人精品午夜在线观看| 中文字幕日韩精品在线| 91成人天堂久久成人| 91在线视频成人| 欧美日韩另类在线| 久久久久www| 美女扒开尿口让男人操亚洲视频网站| 亚洲18私人小影院| 国产视频精品自拍| 欧美激情网友自拍| 亚洲精品综合精品自拍| 狠狠综合久久av一区二区小说| 日韩欧美极品在线观看| 亚洲欧美成人在线| 欧美国产日韩视频| 久久久国产精彩视频美女艺术照福利| 国产精品视频资源| 欧美日韩国产成人高清视频| 亚洲精品国偷自产在线99热| 欧美日韩精品在线观看| 国产精品久久久久久久久久新婚| 九九热这里只有精品免费看| 国模精品视频一区二区三区| 精品亚洲一区二区三区在线播放| 国产日韩在线视频| 影音先锋欧美在线资源| 一区国产精品视频| 国产精品久久国产精品99gif| 久久艳片www.17c.com| 精品国产1区2区| 亚洲精品视频中文字幕| 一区二区三区四区精品| 欧美激情乱人伦一区| 久久躁狠狠躁夜夜爽| 久久99热这里只有精品国产| 亚洲欧美国产va在线影院| www.欧美精品一二三区| 亚洲韩国日本中文字幕| 亚洲第一二三四五区| 欧美精品日韩www.p站| 麻豆精品精华液| 亚洲美女免费精品视频在线观看| 欧美在线一区二区视频| 日韩人在线观看| 成人免费xxxxx在线观看| 综合国产在线观看| 欧美精品18videos性欧| 成人福利视频在线观看| 最近2019中文字幕大全第二页| 国产成人精彩在线视频九色|