WPF XAML 名稱範圍WPF XAML Namescopes

XAML 名稱範圍是識別 XAML 中所定義物件的概念。XAML namescopes are a concept that identifies objects that are defined in XAML. XAML 名稱範圍中的名稱可以用來建立物件的 XAML 定義名稱與其在物件樹狀結構中的執行個體對等項目之間的關聯性。The names in a XAML namescope can be used to establish relationships between the XAML-defined names of objects and their instance equivalents in an object tree. 一般而言,載入 XAML 應用程式的個別 XAML 頁面根時,會建立 WPFWPF Managed 程式碼中的 XAML 名稱範圍。Typically, XAML namescopes in WPFWPF managed code are created when loading the individual XAML page roots for a XAML application. XAML 名稱範圍做為程式設計物件是由 INameScope 介面所定義,也是由實體類別所執行 NameScopeXAML namescopes as the programming object are defined by the INameScope interface and are also implemented by the practical class NameScope.

所載入 XAML 應用程式中的名稱範圍Namescopes in Loaded XAML Applications

在更廣泛的程式設計或電腦科學內容中,程式設計概念通常包括可用來存取物件之唯一識別碼或名稱的原則。In a broader programming or computer science context, programming concepts often include the principle of a unique identifier or name that can be used to access an object. 針對使用識別碼或名稱的系統,在要求該名稱的物件時,名稱範圍會定義程序或技術將在其內搜尋的界限,或是在其中強制執行識別名稱唯一性的界限。For systems that use identifiers or names, the namescope defines the boundaries within which a process or technique will search if an object of that name is requested, or the boundaries wherein uniqueness of identifying names is enforced. 這些一般原則適用於 XAML 名稱範圍。These general principles are true for XAML namescopes. 在 WPF 中,載入 XAML 頁面時,會在頁面的根項目上建立 XAML 名稱範圍。In WPF, XAML namescopes are created on the root element for a XAML page when the page is loaded. 在頁面根開始之 XAML 頁面內所指定的每個名稱都會新增至適當的 XAML 名稱範圍。Each name specified within the XAML page starting at the page root is added to a pertinent XAML namescope.

在 WPF XAML 中,通用根項目的專案 (例如 Page ,且 Window) 一律控制 XAML 名稱範圍。In WPF XAML, elements that are common root elements (such as Page, and Window) always control a XAML namescope. 如果或之類的元素 FrameworkElement FrameworkContentElement 是標記中頁面的根項目,則 XAMLXAML 處理器會 Page 隱含地加入根,以便 Page 提供可運作的 XAML 名稱範圍。If an element such as FrameworkElement or FrameworkContentElement is the root element of the page in markup, a XAMLXAML processor adds a Page root implicitly so that the Page can provide a working XAML namescope.

注意

WPF 建置動作會針對 XAML 生產來建立 XAML 名稱範圍,即使未在 XAMLXAML 標記的任何項目上定義 Namex:Name 屬性也是一樣。WPF build actions create a XAML namescope for a XAML production even if no Name or x:Name attributes are defined on any elements in the XAMLXAML markup.

如果您嘗試在任何 XAML 名稱範圍中使用相同的名稱兩次,則會引發例外狀況。If you try to use the same name twice in any XAML namescope, an exception is raised. 針對具有程式碼後置且為已編譯應用程式一部分的 WPF XAML,在初始標記編譯期間建立頁面的已產生類別時,WPF 建置動作會在建置期間引發例外狀況。For WPF XAML that has code-behind and is part of a compiled application, the exception is raised at build time by WPF build actions, when creating the generated class for the page during the initial markup compile. 針對未透過任何建置動作進行標記編譯的 XAML,在載入 XAML 時,可能會引發 XAML 名稱範圍問題的相關例外狀況。For XAML that is not markup-compiled by any build action, exceptions related to XAML namescope issues might be raised when the XAML is loaded. XAML 設計工具也可能預期會在設計階段發生 XAML 名稱範圍問題。XAML designers might also anticipate XAML namescope issues at design time.

將物件新增至執行階段物件樹狀結構Adding Objects to Runtime Object Trees

剖析 XAML 的時間點代表建立和定義 WPF XAML 名稱範圍的時間點。The moment that XAML is parsed represents the moment in time that a WPF XAML namescope is created and defined. 如果您在剖析已產生該樹狀結構的 XAML 之後的某個時間點,將物件新增至物件樹狀結構,則新物件上的 Namex:Name 值不會自動更新 XAML 名稱範圍中的資訊。If you add an object to an object tree at a point in time after the XAML that produced that tree was parsed, a Name or x:Name value on the new object does not automatically update the information in a XAML namescope. 若要在載入 XAML 之後,將物件的名稱加入 WPF XAML 名稱範圍,您必須 RegisterName 在定義 xaml 名稱範圍的物件(通常是 xaml 網頁根目錄)上呼叫適當的實作為。To add a name for an object into a WPF XAML namescope after XAML is loaded, you must call the appropriate implementation of RegisterName on the object that defines the XAML namescope, which is typically the XAML page root. 如果名稱未註冊,則無法透過的方法(例如)參考加入的物件, FindName 而且您不能將該名稱用於動畫目標。If the name is not registered, the added object cannot be referenced by name through methods such as FindName, and you cannot use that name for animation targeting.

應用程式開發人員最常見的案例是,您將使用在 RegisterName 目前網頁根目錄的 XAML 名稱範圍中註冊名稱。The most common scenario for application developers is that you will use RegisterName to register names into the XAML namescope on the current root of the page. RegisterName 是以動畫的物件為目標之分鏡腳本的重要案例的一部分。RegisterName is part of an important scenario for storyboards that target objects for animations. 如需詳細資訊,請參閱分鏡腳本概觀For more information, see Storyboards Overview.

如果您呼叫 RegisterName 的物件不是定義 XAML 名稱範圍的物件,則名稱仍會註冊至呼叫物件所在的 xaml 名稱範圍,就像您在 RegisterName 定義物件的 xaml 名稱範圍中呼叫一樣。If you call RegisterName on an object other than the object that defines the XAML namescope, the name is still registered to the XAML namescope that the calling object is held within, as if you had called RegisterName on the XAML namescope defining object.

程式碼中的 XAML 名稱範圍XAML Namescopes in Code

您可以在程式碼中建立 XAML 名稱範圍後來加以使用。You can create and then use XAML namescopes in code. 甚至針對純程式碼用法,與 XAML 名稱範圍建立有關的 API 和概念也會相同,因為 WPFWPF 的 XAML 處理器在處理 XAML 本身時會使用這些 API 和概念。The APIs and the concepts involved in XAML namescope creation are the same even for a pure code usage, because the XAML processor for WPFWPF uses these APIs and concepts when it processes XAML itself. 概念和 API 的存在目的主要是可以依名稱在物件樹狀結構內找到物件,而物件樹狀結構一般是在 XAML 中部分或完整定義。The concepts and API exist mainly for the purpose of being able to find objects by name within an object tree that is typically defined partially or entirely in XAML.

對於以程式設計方式建立的應用程式,而不是從載入的 XAML,定義 XAML 名稱範圍的物件必須 INameScope FrameworkElement 實作為或 FrameworkContentElement 衍生類別,才能支援在其實例上建立 XAML 名稱範圍。For applications that are created programmatically, and not from loaded XAML, the object that defines a XAML namescope must implement INameScope, or be a FrameworkElement or FrameworkContentElement derived class, in order to support creation of a XAML namescope on its instances.

此外,針對 XAML 處理器未載入和處理的任何項目,預設都不會建立或初始化物件的 XAML 名稱範圍。Also, for any element that is not loaded and processed by a XAML processor, the XAML namescope for the object is not created or initialized by default. 您必須針對任何您要註冊名稱的物件,明確建立新的 XAML 名稱範圍。You must explicitly create a new XAML namescope for any object that you intend to register names into subsequently. 若要建立 XAML 名稱範圍,您可以呼叫靜態 SetNameScope 方法。To create a XAML namescope, you call the static SetNameScope method. 指定將作為參數的物件,並指定新的函式 dependencyObject NameScope 呼叫做為 value 參數。Specify the object that will own it as the dependencyObject parameter, and a new NameScope constructor call as the value parameter.

如果為 for 提供的 dependencyObject 物件 SetNameScope 不是實作為 INameScopeFrameworkElementFrameworkContentElement RegisterName 在任何子項目上呼叫,則不會有任何作用。If the object provided as dependencyObject for SetNameScope is not a INameScope implementation, FrameworkElement or FrameworkContentElement, calling RegisterName on any child elements will have no effect. 如果您無法明確地建立新的 XAML 名稱範圍,則呼叫 RegisterName 將會引發例外狀況。If you fail to create the new XAML namescope explicitly, then calls to RegisterName will raise an exception.

如需在程式碼中使用 XAML 名稱範圍 API 的範例,請參閱定義名稱範圍For an example of using XAML namescope APIs in code, see Define a Name Scope.

樣式和範本中的 XAML 名稱範圍XAML Namescopes in Styles and Templates

WPFWPF 中的樣式和範本可以用更簡單的方式重複使用和重新套用內容。Styles and templates in WPFWPF provide the ability to reuse and reapply content in a straightforward way. 不過,樣式和範本可能也包括具有範本層級所定義之 XAML 名稱的項目。However, styles and templates might also include elements with XAML names defined at the template level. 可能會在頁面中多次使用這個相同的範本。That same template might be used multiple times in a page. 因此,樣式和範本都會定義其專屬 XAML 名稱範圍,這與物件樹狀結構中套用樣式或範本的位置無關。For this reason, styles and templates both define their own XAML namescopes, independent of whatever location in an object tree where the style or template is applied.

請考慮下列範例:Consider the following example:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

在這裡,相同的範本會套用至兩個不同的按鈕。Here, the same template is applied to two different buttons. 如果範本沒有離散 XAML 名稱範圍,則範本中所使用的 TheBorder 名稱會導致 XAML 名稱範圍中的名稱衝突。If templates did not have discrete XAML namescopes, the TheBorder name used in the template would cause a name collision in the XAML namescope. 範本的每個具現化都有其專屬的 XAML 名稱範圍;因此,在此範例中,每個具現化範本的 XAML 名稱範圍都只會包含一個名稱。Each instantiation of the template has its own XAML namescope, so in this example each instantiated template's XAML namescope would contain exactly one name.

樣式也會定義其專屬的 XAML 名稱範圍;因此,分鏡腳本的各部分一般可以獲指派特定名稱。Styles also define their own XAML namescope, mostly so that parts of storyboards can have particular names assigned. 即使已在控制項自訂時重新定義範本,這些名稱還是可以啟用將目標設為該名稱之項目的控制項特定行為。These names enable control specific behaviors that will target elements of that name, even if the template was re-defined as part of control customization.

因為不同的 XAML 名稱範圍,所以在範本中尋找具名項目會比在頁面中尋找非範本具名項目更具挑戰。Because of the separate XAML namescopes, finding named elements in a template is more challenging than finding a non-templated named element in a page. 您必須先取得套用 Template 範本之控制項的屬性值,以判斷套用的範本。You first need to determine the applied template, by getting the Template property value of the control where the template is applied. 然後,您可以呼叫的範本版本 FindName ,傳遞套用範本作為第二個參數的控制項。Then, you call the template version of FindName, passing the control where the template was applied as the second parameter.

如果您是控制項作者,而您產生的慣例是套用的範本中特定的命名元素是由控制項本身所定義之行為的目標,則可以使用 GetTemplateChild 控制項執行程式碼中的方法。If you are a control author and you are generating a convention where a particular named element in an applied template is the target for a behavior that is defined by the control itself, you can use the GetTemplateChild method from your control implementation code. GetTemplateChild方法會受到保護,因此只有控制項作者可以存取它。The GetTemplateChild method is protected, so only the control author has access to it.

如果您是在範本內工作,且需要取得套用範本的 XAML 名稱範圍,請取得的值 TemplatedParent ,然後在 FindName 該處呼叫。If you are working from within a template, and need to get to the XAML namescope where the template is applied, get the value of TemplatedParent, and then call FindName there. 在範本內運作的範例就是您要撰寫事件處理常式實作,其中,將從已套用範本中的項目引發事件。An example of working within the template would be if you are writing the event handler implementation where the event will be raised from an element in an applied template.

FrameworkElement 具有 FindNameRegisterNameUnregisterName 方法。FrameworkElement has FindName, RegisterName and UnregisterName methods. 如果您在其上呼叫這些方法的物件擁有 XAML 名稱範圍,則方法會呼叫相關 XAML 名稱範圍的方法。If the object you call these methods on owns a XAML namescope, the methods call into the methods of the relevant XAML namescope. 否則,會檢查父項目,確認它是否擁有 XAML 名稱範圍,而且此程序會遞迴地執行,直到找到 XAML 名稱範圍 (因為 XAML 處理器行為,所以根一定會有 XAML 名稱範圍)。Otherwise, the parent element is checked to see if it owns a XAML namescope, and this process continues recursively until a XAML namescope is found (because of the XAML processor behavior, there is guaranteed to be a XAML namescope at the root). FrameworkContentElement 具有類似的行為,但不 FrameworkContentElement 會擁有 XAML 名稱範圍的例外狀況。FrameworkContentElement has analogous behaviors, with the exception that no FrameworkContentElement will ever own a XAML namescope. 這些方法存在於上 FrameworkContentElement ,因此可以將呼叫最後轉送至 FrameworkElement 父元素。The methods exist on FrameworkContentElement so that the calls can be forwarded eventually to a FrameworkElement parent element.

SetNameScope 用來將新的 XAML 名稱範圍對應至現有的物件。SetNameScope is used to map a new XAML namescope to an existing object. 您可以呼叫 SetNameScope 一次以上,以便重設或清除 XAML 名稱範圍,但這不是常見的使用方式。You can call SetNameScope more than once in order to reset or clear the XAML namescope, but that is not a common usage. 此外, GetNameScope 通常不會從程式碼使用。Also, GetNameScope is not typically used from code.

XAML 名稱範圍實作XAML Namescope Implementations

下列類別會 INameScope 直接執行:The following classes implement INameScope directly:

ResourceDictionary 不使用 XAML 名稱或名稱範圍;它會改為使用索引鍵,因為它是字典的執行。ResourceDictionary does not use XAML names or namescopes ; it uses keys instead, because it is a dictionary implementation. 唯一實行的原因 ResourceDictionary INameScope 是,它可能會引發例外狀況給使用者程式碼,以協助澄清真正的 xaml 名稱範圍與處理索引鍵之間的區別 ResourceDictionary ,以及確保 XAML 名稱範圍不會套用至 ResourceDictionary by 父元素。The only reason that ResourceDictionary implements INameScope is so it can raise exceptions to user code that help clarify the distinction between a true XAML namescope and how a ResourceDictionary handles keys, and also to assure that XAML namescopes are not applied to a ResourceDictionary by parent elements.

FrameworkTemplateStyle INameScope 透過明確的介面定義來執行。FrameworkTemplate and Style implement INameScope through explicit interface definitions. 明確的執行可讓這些 XAML 名稱範圍在透過介面存取時以傳統方式運作 INameScope ,這就是內部進程如何傳達 XAML 名稱範圍 WPFWPFThe explicit implementations allow these XAML namescopes to behave conventionally when they are accessed through the INameScope interface, which is how XAML namescopes are communicated by WPFWPF internal processes. 但是明確的介面定義不是和的傳統 API 介面的一部分 FrameworkTemplate Style ,因為您很少需要 INameScope 直接呼叫方法 FrameworkTemplate Style ,而是改為使用其他 API (例如) GetTemplateChildBut the explicit interface definitions are not part of the conventional API surface of FrameworkTemplate and Style, because you seldom need to call the INameScope methods on FrameworkTemplate and Style directly, and instead would use other API such as GetTemplateChild.

下列類別會定義自己的 XAML 名稱範圍,方法是使用 System.Windows.NameScope helper 類別,並透過附加屬性連接到其 xaml 名稱範圍的實作為 NameScope.NameScopeThe following classes define their own XAML namescope, by using the System.Windows.NameScope helper class and connecting to its XAML namescope implementation through the NameScope.NameScope attached property:

另請參閱See also