Microsoft 文档对此有一些很好的信息:
默认情况下,当 .NET Framework XAML 服务 API 使用时,主 XAML 名称范围在单个 XAML 产品的 XAML 根元素中定义,并包含该 XAML 产品中包含的元素.
这里的要点是,任何 Xaml 文档中的根元素都有为其创建的名称范围。 不管元素是否实现了INameScope(事实上,没有核心 UI 元素实现),都会发生这种情况。
框架可以定义可能出现在单个 XAML 产品中的其他离散 XAML 名称范围,以解决特定场景。例如,在 WPF 中,新的 XAML 名称范围由任何模板定义和创建,该模板也在该 XAML 产品上定义。有关 XAML 名称范围的更多信息(为 WPF 编写,但与许多 XAML 名称范围概念相关),请参阅WPF XAML Namescopes。
除了为根元素创建的名称范围之外,还为在 Xaml 产品中定义的任何模板隐式创建了名称范围。这应该不足为奇,因为FrameworkTemplate 实现了INameScope,因此DataTemplate 和ControlTemplate 也是如此。还为 Style 元素创建名称范围。
您可能会注意到ResourceDictionary 也实现了INameScope,但它有点边缘情况:资源字典中的对象名称实际上未在任何运行时名称范围内注册。如果您查看实现,您会看到它的INameScope 方法要么抛出NotSupportedException,不执行任何操作,要么返回null。这种设计很好地包含了名称。它们被阻止在任何父范围中注册,同时使它们可用于有限的目的,例如在 Binding 上使用 ElementName 引用。重申一下,资源字典作为名称范围是一种极端情况,实际上,您永远不必考虑这种情况。
除了上面概述的隐式创建的范围之外,还会为任何对象创建节点的 Xaml 解析器框架创建一个新的名称范围,其中创建的对象实现 INameScope。与所有名称范围一样,已注册的名称在该范围内必须是唯一的;但是,它们可能会与堆栈中其他名称范围内的名称发生冲突。
从 Xaml 中具体化对象时,XamlObjectWriter 通过在堆栈中向上查找具有名称范围的帧来解析名称,一旦找到包含所需名称的范围就停止。例如,在评估来自 x:Reference 指令的延迟引用时,就会发生这种情况。
它是否完全依赖INameScope接口,检查instance is INameScope?
它是否依赖于boolean 属性XamlType.IsNameScope?
通常是后者,但该标志是通过确定一个类型是否可分配给 Xaml INameScope 类型来设置的,该类型映射到 System.Windows.Markup.INameScope。它不检查运行时实例,而是检查相应对象创建节点的XamlType。从概念上讲,检查类似于typeof(INameScope).IsAssignableFrom(instanceType)。
虽然你没有问,但为了完整起见,我想谈谈最后一点:
对象何时在名称范围内注册?
这发生在两种情况下:
- 您在 Xaml 元素上显式设置了
x:Name 伪属性;
- 您设置了类似
FrameworkElement.Name 的属性,该属性被定义为运行时名称属性。
像FrameworkElement 这样的类型有自己的Name 属性,而不是强制开发人员分别指定Name 和x:Name,他们提供了一种将CLR 属性映射到x:Name 的方法。如果您查看FrameworkElement 的来源,您将看到[RuntimeNameProperty("Name")] 属性。这会告诉 Xaml 基础结构任何FrameworkElement 上的Name 属性对应于x:Name,并且设置一个应该会导致另一个也被设置。请注意,运行时名称属性可以具有任何有效名称;它不需要被称为Name。