WPF--名称范围

Posted X·3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF--名称范围相关的知识,希望对你有一定的参考价值。

WPF--名称范围

名称范围既是一种概念,也是用于存储对象的XAML定义名称及其实例等效项之间的关系的编程对象。加载XAML应用程序的页面时,即在 WPF 托管代码中创建了名称范围。作为编程对象的名称范围由INameScope接口定义,并且还由实际类NameScope实现。

加载的XAML应用程序中的名称范围

处理XAML页时,即对该页的根元素创建了名称范围。该页中指定的每个名称都会添加到相关的名称范围中。作为常见根元素(例如Page和Window)的元素总是控制名称范围。如果在标记中某个元素(例如FrameworkElement或 FrameworkContentElement)是页的根元素,则XAML处理器会隐式添加一个Page根元素,以便Page可以提供一个名称范围。即使最初在XAML中没有定义 Name 或x:Name属性,也会创建一个名称范围。

如果试图在任意名称范围中两次使用同一个名称,则会引发异常。对于具有代码隐藏并且是已编译的应用程序的一部分的XAML,在创建页的已生成类时会引发该异常。

将元素添加到已分析的元素树

若要在初始的加载和处理之后向元素树添加任何元素,都必须对定义名称范围的类调用相应的RegisterName的实现。否则,无法通过FindName等方法按名称引用添加的对象。仅设置Name属性(或 x:Name属性)不会将该名称注册到任何名称范围中。将命名的元素添加到具有名称范围的元素树中也不会将此名称注册到名称范围中。尽管名称范围可以嵌套,但通常您应该将名称注册到根元素上存在的名称范围中,这样您的名称范围位置便可与在等效的加载XAML页中可能已创建的名称范围并列。 应用程序开发人员最常用的方案是使用 RegisterName将名称注册到当前根元素的名称范围中。RegisterName是查找将作为动画运行的演示图板的一种重要方案的一部分。有关更多信息,请参见演示图板概述。如果您对同一逻辑树中的非根元素的元素调用RegisterName,则该名称仍然会注册到最靠近根元素的元素,就好像对该根元素调用了RegisterName一样。

代码中的名称范围

对于以编程方式创建(而不是来自加载的XAML)的应用程序,若要支持名称范围,根元素必须实现INameScope、或者必须是FrameworkElement或FrameworkContentElement派生类。

此外,对于不是由XAML处理器加载和处理的任何元素,默认情况下不会创建或初始化该对象的名称范围。必须为随后要向其中注册名称的任何元素显式创建新的名称范围。若要为元素创建名称范围,可调用静态SetNameScope方法。将该元素指定为dependencyObject参数,并且将新的NameScope构造函数调用指定为value参数。

如果作为SetNameScope的dependencyObject提供的对象不是INameScope实现,也不是FrameworkElement或FrameworkContentElement,那么,对任何子元素调用RegisterName均无效。如果您无法显式创建新的名称范围,则调用RegisterName将引发异常。

样式和模板中的名称范围

WPF中的样式和模板提供了以简单的方法重新使用和重新应用内容的功能,但样式和模板可能还包括具有在模板级别指定的名称的元素。同一个模板可能在某个页中被多次重复使用。因此,样式和模板都定义其自己的名称范围,而与样式或模板所应用到的包含页无关。

请看下面的示例:

此处,同一个模板被应用到两个不同的按钮。如果模板没有独立的名称范围,则该模板中用到的TheBorder名称会导致名称冲突。模板的每个实例化都有其自已的名称范围,因此在本示例中每个实例化模板的名称范围都只包含一个名称。

样式也具有其自己的名称范围,因此大多数情况下演示图板的某些部分会分配有特殊的名称。即使模板重新定义为控件自定义项的一部分,这些名称也会启用以具有此名称的元素为目标的控件特定行为。

由于名称范围是独立的,因此在模板中查找命名的元素比在页中查找非模板化的元素更具有挑战性。首先需要确定所应用的模板,方法是获取该模板所应用到的控件的Template属性值。然后,调用FindName的模板版本,将模板所应用到的控件作为第二个参数进行传递。

如果您是控件作者,您要生成一个约定,即所应用的模板中的特定命名元素是控件本身所定义的行为的目标,则可以在控件实现代码中使用GetTemplateChild方法。由于GetTemplateChild方法是受保护的,因此只有控件作者才可以访问它。

如果您正在使用模板,并且需要用到该模板所应用到的名称范围,则获取TemplatedParent,然后调用其中的FindName。举一个使用模板的例子:您正在编写事件处理程序实现,其中该事件将从所应用的模板中的元素被引发。

名称范围和名称相关的API

FrameworkElement具有FindName、RegisterName和UnregisterName方法。如果您对其调用这些方法的元素拥有名称范围,则这些元素方法仅调入名称范围方法。否则,会查看其父元素是否具有名称范围,此进程会以递归方式继续执行,直到找到一个名称范围为止(由于XAML处理器行为的原因,可以保证在根元素有名称范围)。FrameworkContentElement具有类似的行为,所不同的是FrameworkContentElement从不会有名称范围。在FrameworkContentElement上存在上述方法,因此这些调用最终可以转发到FrameworkElement父元素。

SetNameScope用于将新的名称范围映射到现有的对象。您可以多次调用SetNameScope以重置或清除名称范围,但这种用法并不常见。此外,通常不通过代码使用GetNameScope。

名称范围实现

下面的类直接实现INameScope:

NameScope

Style

ResourceDictionary

FrameworkTemplate

ResourceDictionary不使用名称范围,而是使用键,原因是它是一种字典哈希表实现。ResourceDictionary之所以实现INameScope,其唯一的原因是它可以对用户代码引发异常,从而有助于澄清真正的名称范围和ResourceDictionary处理键的方式之间的区别,此外,还可以保证名称范围不会被父元素特别应用到ResourceDictionary。

FrameworkTemplate和Style通过显式接口定义实现INameScope。这些显式实现允许这些名称范围在通过INameScope接口进行访问时表现为常规行为,这是名称范围与 WPF 内部进程进行通信的方式。但是,这些显式接口定义不是FrameworkTemplate和Style的常规名称范围的一部分,原因是几乎不需要对FrameworkTemplate和Style直接调用INameScope方法。

下面的类都定义自己的名称范围,方法是使用 System.Windows..::.NameScope 帮助器类并通过NameScope附加属性连接到相应的名称范围实现:

FrameworkElement

FrameworkContentElement

以上是关于WPF--名称范围的主要内容,如果未能解决你的问题,请参考以下文章

WPF--名称范围

WPF--名称范围

Windows Phone开发(21):做一个简单的绘图板

大神,还是请问一个Excel的问题,打开Excel提示安装自定义项出错,值不在预期范围内。下面是详细信息感谢

WPF--样式设置

TFT液晶显示屏之绘图板应用