在WPF中,x:Name和Name属性有什么区别?

662
有时候似乎Namex:Name属性是可以互换的。那它们之间的确切区别是什么,使用其中一个比另一个更好呢?如果使用方式不当会有性能或内存方面的影响吗?

2
回应表明始终使用 x:Name 是有效的。我不得不将其更改为 Name,否则我无法在我的 .xaml.cs 代码中引用控件,因此我假设它不再是始终有效的情况。 - Ortund
15个回答

526
在 XAML 中,实际上只有一个名称,即 x:Name。框架(如 WPF)可以使用 RuntimeNamePropertyAttribute 在类上指定属性映射到 XAML 的 x:Name,从而将其属性映射到 XAML 的 x:Name。 这么做的原因是为了允许那些在运行时已经具有“名称”概念的框架(如 WPF)。例如,在 WPF 中,FrameworkElement 引入了一个 Name 属性。 通常,类不需要存储 x:Name 的名称即可使用。对于 XAML,x:Name 只是生成用于在代码后台类中存储值的字段。运行时对该映射的处理取决于框架。 那么,为什么要有两种方法来做同一件事呢?简单地说,这是因为有两个概念映射到一个属性。WPF 希望在运行时保留元素的名称(这可以通过 Bind 等方式使用),而 XAML 需要知道您想通过代码后台类中的哪些字段访问这些元素。WPF 将这两者联系起来,将 Name 属性标记为 x:Name 的别名。 未来,XAML 将具有更多使用 x:Name 的功能,例如允许您通过名称引用其他对象来设置属性,但在 3.5 及之前版本中,它仅用于创建字段。 使用哪种方法其实是一种风格问题,而不是技术问题。我将把这个问题留给其他人来推荐。 另请参见 AutomationProperties.Name VS x:Name,其中 AutomationProperties.Name 被辅助工具和某些测试工具使用。

2
在Visual Studio 2010中,当您通过设计师编辑XAML时,Name属性被设置(而不是x:Name)。看起来微软鼓励使用Name而不是x:Name,因此我想这就是事实上的标准。 - Nebula
13
通常情况下,我认为这两个是不能互换的。给用户控件命名需要使用 x:Name,因为 Name 无法创建可在代码后台中识别的字段。尽管如此,我仍然不知道为什么会发生这种情况。 - Libor
7
他们并不是,我也没有意思暗示他们是。在WPF中,如果一个元素有“Name”属性,它们意思相同。如果该元素没有“Name”属性,则必须使用“x:Name”。 - chuckj
2
@Libor 今天,对于任何派生自“FrameworkElement”的类型(包括您在XAML中使用的大多数类型,包括UserControl),无论您使用Name还是x:Name都没有任何区别,成员将在任何情况下正确生成。这是因为“FrameworkElement”被装饰了[RuntimeNameProperty("Name")] - bitbonk

113

它们不是同一件事情。

x:Name 是一个 XAML 的概念,主要用于引用元素。当您给一个元素设置 x:Name 属性时,“指定的 x:Name 成为处理 XAML 时在底层代码中创建的字段的名称,该字段保存对对象的引用。”(MSDN) 因此,这是一个由设计生成的字段,默认情况下具有内部访问权限。

NameFrameworkElement 的现有字符串属性,以 XAML 属性的形式列出,就像其他 WPF 元素属性一样。

因此,这也意味着 x:Name 可以用于更广泛的对象。这是一种技术,使 XAML 中的任何东西都能被给定名称引用。


9
为什么Binding.ElementName既可以使用Name属性,也可以使用x:Name属性?似乎x:Name属性不仅用于在生成的代码中命名字段,而且在运行时还可用于元数据。 - Drew Noakes
2
它是一个类似于WinForms编辑器设计属性中的Name字段的生成字段。在那里,您可以在属性列表中放置一个名称,它就成为一个字段的名称。这是相同的行为。当然,它在运行时可用,因为它是编译到代码后面的内部字段。Binding.ElementName检查任何一种情况,这就是xaml编辑器的“魔法”,x:Name本身并不是神奇的。 - Kenan E. K.
无论您使用x:Name还是Name,都将生成一个字段。对于所有派生自FrameworkElement的类型(大多数您在XAML中使用的类型),x:Name和Name没有区别,只有一个例外:如果您想给UserControl命名,并且该UserControl在您也想要使用它的同一程序集中声明,则必须使用x:Name,因为XAML解析器的限制。 - bitbonk

48

x:Name和Name引用了不同的命名空间。

x:name是对Xaml文件顶部默认定义的x命名空间的引用。

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

仅仅是说Name使用默认的下面命名空间。

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

x:Name 的意思是使用具有x别名的命名空间。x 是默认值,大多数人都使用它,但你可以将其更改为任何你喜欢的名称。

xmlns:foo="http://schemas.microsoft.com/winfx/2006/xaml"

因此,你的引用将是foo:name

在WPF中定义和使用命名空间


好的,让我们以不同的方式来看待这个问题。比如说,你将一个按钮拖放到你的Xaml页面上。你可以通过两种方式引用它:x:namename。所有的xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"都是对多个命名空间的引用。由于xaml包含了Control命名空间(不确定是否完全正确),而presentation则包含了FrameworkElementButton类的继承模式为:

Button : ButtonBase
ButtonBase : ContentControl, ICommandSource
ContentControl : Control, IAddChild
Control : FrameworkElement
FrameworkElement : UIElement, IFrameworkInputElement, 
                    IInputElement, ISupportInitialize, IHaveResources
因此,任何从FrameworkElement继承的内容都可以访问所有公共属性。因此,在Button的情况下,它从FrameworkElement获取其Name属性,在层次结构树的顶部。因此,您可以说x:NameName,它们都将访问FrameworkElement的getter/setter。

MSDN参考

WPF定义了一个CLR属性,由XAML处理器消耗,以将多个CLR命名空间映射到单个XML命名空间。 XmlnsDefinitionAttribute属性放置在生成程序集的源代码中的程序集级别上。 WPF程序集源代码使用此属性将各种常见命名空间(例如System.Windows和System.Windows.Controls)映射到http://schemas.microsoft.com/winfx/2006/xaml/presentation命名空间。

因此,程序集属性将类似于:

PresentationFramework.dll - XmlnsDefinitionAttribute:

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows")]

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows.Data")]

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows.Navigation")]

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows.Shapes")]

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows.Documents")]

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "System.Windows.Controls")]  

1
我认为http://schemas.microsoft.com/winfx/2006/xaml并不包含Control,因为你可以在XAML中直接使用它而不需要x命名空间:<Control /> - Drew Noakes

28
它们其实是同一回事,很多框架元素本身都会暴露一个名字属性,但对于那些没有的,你可以使用x:name - 我通常都只用x:name,因为它适用于所有情况。 控件可以自己暴露一个名字属性作为依赖属性(因为它们需要在内部使用该依赖属性),或者选择不暴露。 更多详细信息请参考微软文档这里这里。 一些WPF框架级应用程序可能可以避免使用x:Name属性,因为在WPF命名空间中指定的Name依赖属性在几个重要的基类(如FrameworkElement/FrameworkContentElement)中满足相同的目的。在某些常见的XAML和框架场景中,仍然需要对没有Name属性的元素进行代码访问,尤其是在某些动画和故事板支持类中。例如,如果您打算从代码中引用XAML中创建的时间轴和变换,则应在其中指定x:Name。

如果Name在类上可用作属性,则可以将Name和x:Name互换使用作为属性,但如果在同一元素上同时指定两者,则会导致错误。


4
如果没有区别,为什么会有两种做同一件事的方法呢?这两种方式都存在于WPF的第一个版本中。 - Drew Noakes
@Steve,我没有在这个问题的任何答案上投反对票,尽管到目前为止它们都不是很合适。 - Drew Noakes
1
我不明白为什么一个回答不仅可以给出答案,还可以提供连接到MSDN获取更多信息的链接,为什么不合适呢? :-) - Steven Robbins
5
@Steve,你的原始回答没有回答我的问题,这就是我留下评论的原因。我不是在寻找盲目信仰的“按照这种方式去做”,而是希望得到一个深入的答案,解释为什么会存在两种方法,即使其中一种方法并不总是有效的。技术上的正确并不等同于适当。你的更新回答好多了。 - Drew Noakes
1
这里的答案与 http://wpfwiki.com/WPF%20Q16.4.ashx 相似。x:Name 为控件指定一个名称,以在代码后台中使用。某些类将提供 Name 属性以实现相同的目的。对于这些类,x:name 和 name 没有区别。 - Vegar

14

X:Name(名称)可能会导致内存问题,特别是当您使用自定义控件时。它会为NameScope条目保留一个内存位置。

我建议除非必须,否则不要使用x:Name。


同意。我曾经参与过一个自助应用程序,它存在许多内存泄漏问题,之前的开发团队的解决方法只是强制重启。其中许多泄漏很容易识别。但是,在通过 IntelliTrace 和 JustTrace 找到并修复了些泄漏后,一些引用仍然逃脱了隐式和显式垃圾回收的清理。我读了这篇文章:http://support.scichart.com/index.php?/News/NewsItem/View/21/wpf-xname-memory-leak--how-to-clear-memory-in-scichart 发现减少 x:Name 也可以进一步改善性能。 - MachinusX
3
我的理解是,这会影响到 Namex:Name,因为两者都被添加到了 NameScope 中。如果您需要在元素上设置名称,那么就无法避免这一点。您可以通过 FrameworkElement.RegisterName("elementname") 在没有名称的元素上重现代码问题。但是,如果您调用 FrameworkElement.UnregisterName("elementname"),它可以被“取消引用”。 - Adam Caviness

12

名称:

  1. 只能用于FrameworkElement和FrameworkContentElement的后代元素;
  2. 可以通过SetValue()方法和类似属性的方式从代码后台设置。

x:Name:

  1. 几乎可用于所有XAML元素;
  2. 无法通过SetValue()方法从代码后台设置;它只能在对象上使用属性语法进行设置,因为它是一个指令。

在XAML中同时使用这两个指令会导致异常:如果XAML是标记编译的,则异常将发生在标记编译过程中,否则它会在加载时发生。


8
唯一的区别在于,如果您将用户控件添加到同一程序集中的控件中,则名称将无法识别您的控件,并且您将收到错误消息“在相同的程序集中使用x:Name来控制”。因此,x:Name是WPF中命名控件的版本。Name仅用作Winform遗留问题。他们想要区分WPF和winforms中控件的命名,因为他们在Xaml中使用属性来识别来自其他程序集的控件,所以他们使用x:作为控件名称的符号。 只需记住,不要仅仅为了保持名称而对控件进行命名,因为它会作为空内容存储在内存中,并且会出现警告,表示针对控件应用了名称,但其从未被使用过。

8

x:Name的意思是:在代码后台创建一个字段来保存对该对象的引用。

Name的意思是:设置该对象的名称属性。


1
这并不完全正确;它们都可以从代码后台访问,但有趣的是只有x:Name可以在运行时更新。有点疯狂。 - user1228

4

我总是使用x:Name变量。 我不知道这是否会影响性能,但我发现它更容易实现以下功能。 如果您拥有自己的用户控件,这些控件驻留在另一个程序集中,仅使用“名称”属性可能不足以满足需求。因此,使用x:Name属性更加方便。


6
如果没有差别,那为什么会存在两种做同一件事的方法呢?这两种方式都在WPF的最初版本中存在。 - Drew Noakes

3
这不是WPF项目,而是标准的XML项目。 BtBh 已经正确回答了问题,x指的是默认命名空间。在XML中,当您没有为元素/属性添加命名空间前缀时,它会假定您想要使用默认命名空间。因此,仅键入Name就等同于x:Name的简写形式。有关XML命名空间的更多详细信息,请参见链接文本

1
感到心动,但是 -1 x: 指的是不同的 XML 命名空间,但这并不是关于何时需要使用其中一个的有用答案。 :/ - Tim Lovell-Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,