国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C# - WPF中NameScope的查找規則詳解

WPF中NameScope的查找規則詳解

2022-03-02 14:20呂毅 C#

這篇文章主要給大家介紹了關于WPF中NameScope的查找規則的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

我們在 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 接口只用來管理一個范圍之內的名稱。它包含下面三個方法:

?
1
2
3
4
5
6
public interface INameScope
{
 object FindName(string name);
 void RegisterName(string name, object scopedElement);
 void UnregisterName(string name);
}

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 代碼中的注釋):

?
1
2
3
4
5
6
7
8
<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 的功能:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/// <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,重寫時只是單純的返回了一個內部管理的字段而已:

?
1
2
3
4
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。

總結

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

原文鏈接:https://walterlv.com/post/namescope-of-wpf.html

延伸 · 閱讀

精彩推薦
  • C#C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    這篇文章主要介紹了C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題,簡單描述了訪問者模式的定義并結合具體實例形式分析了C#使用訪問者模式解決長...

    GhostRider9502022-01-21
  • C#C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    這篇文章主要介紹了C# 實現對PPT文檔加密、解密及重置密碼的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下...

    E-iceblue5012022-02-12
  • C#Unity3D實現虛擬按鈕控制人物移動效果

    Unity3D實現虛擬按鈕控制人物移動效果

    這篇文章主要為大家詳細介紹了Unity3D實現虛擬按鈕控制人物移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    shenqingyu060520232410972022-03-11
  • C#深入解析C#中的交錯數組與隱式類型的數組

    深入解析C#中的交錯數組與隱式類型的數組

    這篇文章主要介紹了深入解析C#中的交錯數組與隱式類型的數組,隱式類型的數組通常與匿名類型以及對象初始值設定項和集合初始值設定項一起使用,需要的...

    C#教程網6172021-11-09
  • C#C#裁剪,縮放,清晰度,水印處理操作示例

    C#裁剪,縮放,清晰度,水印處理操作示例

    這篇文章主要為大家詳細介紹了C#裁剪,縮放,清晰度,水印處理操作示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    吳 劍8332021-12-08
  • C#C#通過KD樹進行距離最近點的查找

    C#通過KD樹進行距離最近點的查找

    這篇文章主要為大家詳細介紹了C#通過KD樹進行距離最近點的查找,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    帆帆帆6112022-01-22
  • C#C#實現XML文件讀取

    C#實現XML文件讀取

    這篇文章主要為大家詳細介紹了C#實現XML文件讀取的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Just_for_Myself6702022-02-22
  • C#WPF 自定義雷達圖開發實例教程

    WPF 自定義雷達圖開發實例教程

    這篇文章主要介紹了WPF 自定義雷達圖開發實例教程,本文介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下...

    WinterFish13112021-12-06
主站蜘蛛池模板: 日韩免费一区二区 | 午夜成人免费视频 | 中文字幕成人 | 综合五月网 | 一区二区在线不卡 | 激情亚洲 | 久久99精品国产麻豆婷婷 | 日韩av免费看 | 国产一区a | 久久男人天堂 | 黄网站在线观看 | 亚洲午夜网 | 999久久久国产999久久久 | 亚洲欧美综合乱码精品成人网 | 最新中文字幕视频 | 欧美日韩亚洲系列 | 欧美中文一区二区三区 | 欧美日韩一区二区三区视频 | 亚洲欧洲综合 | 在线观看成人 | 成人网址在线观看 | 久久久久久久久久久国产 | 欧美综合第一页 | 国产一区二区三区四区五区密私 | 日韩成人在线观看 | 中文字幕精品一区久久久久 | 成人精品视频在线观看 | 亚洲一区二区精品 | 免费观看日本视频 | 国产伦乱 | 欧美大片aaaa在线观看 | 国产日韩一级片 | www.伊人| 激情网页 | 媚黑视频 | 亚洲日本韩国在线观看 | 蜜臀久久精品99国产精品日本 | 99久久久久 | 日韩三级 | 久久五月天婷婷 | 北条麻妃一区二区三区中文字幕 |