x:Name:一个是可视树,Name:一个是逻辑树属性 都是指向某个元素异曲同工 官方解释: x:Name: 唯一标识对象元素,以便于从代码隐藏或通用代码中访问实例化的元素。x:Name 一旦应用于支持编程模型,便可被视为与由构造函数返回的用于保存对象引用的变量等效。 Name: 获取或设置元素的标识名称。该名称提供一个引用,以便当 XAML 处理器在处理过程中构造标记元素之后,代码隐藏(如事件处理程序代码)可以对该元素进行引用。这是一个依赖项属性。 有些 WPF 框架级别的应用程序可能能够完全避免使用 x:Name 属性,因为在 WPF 命名空间内为几个重要基类(如 FrameworkElement/FrameworkContentElement)指定的 Name 依赖项属性也具有此用途。仍然有一些常见的 XAML 以及框架方案需要在不使用 Name 属性的情况下通过代码访问元素,这种情况在某些动画和演示图板支持类中最为突出。例如,您应当在时间线以及在 XAML 中创建的转换上指定 x:Name,前提是您计划在代码中引用它们。 如果 Name 可用作类的一个属性,则 Name 和 x:Name 可作为属性互换使用,但如果在同一元素上同时指定了这两者,则将产生错误。
大家都知道,XAML是“用来设计UI”的,设计师用XAML设计出来的UI其后台代码(程序逻辑)可以由程序员用C#或者VB去写——这叫做Code-behind。实际上,设计师用XAML和程序用C#都是在构建同一个类,换句话说就是:把一个类劈成两半,与UI相关的那半由设计师用XAML写,与逻辑相关的那半由程序员用C#写。
.NET之所以支持这种劈开写的功能,得益于partial这个关键字。请大家看这两段代码 // For UI public partial class Car { Color bodyColor; Color windowColor; Polygon door; Polygon seat; } // For logic public partial class Car { public void Accelerate() { /*80, 90... 120, 140....1200...flying...*/} public void Break() {/*zizizizizizizizizi....*/ } } public class Car { // UI Color bodyColor; Color windowColor; Polygon door; Polygon seat; // logic public void Accelerate() { /*80, 90... 120, 140....1200...flying...*/} public void Break() {/*zizizizizizizizizi....*/ } } 实际效果是完全一样的。只是前者是把UI和逻辑劈开写,后者是混在一起写罢了。 劈开的确是劈开了,但让设计师用C#代码去实现UI恐怕不现实——让Blend直接生成C#不是不可能是事情,只是C#描述UI太不直观了。于是,微软更进一步,把界面描述语言又向设计师方向推进了一层,也就是XAML语言。于是,开发和设计的格局就变成了这样: 有了XAML和将XAML解析为C#/VB的解析器,设计师们就能以自己最高的工作效率与程序员们合作开发软件了。目前关于XAML是如何解析成C#/VB的资料非常少。 Name揭秘 下面让我们把目光集中在XAML->C#的解析上来,看看Name和x:Name的本质是什么。 让我们看一段代码: <Window x:Class="WpfApplication2.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="100" Width="300" Background="SteelBlue"> <StackPanel> <TextBox Name="textBox1"/> <TextBox Name="textBox2"/> <Button Content="Show Name" Click="Button_Click"/> </StackPanel> <x:Code> <![CDATA[ private void Button_Click(object sender, RoutedEventArgs e) { Button btn = e.OriginalSource as Button; textBox1.Text = btn.Name; textBox2.Name = "Made_in_China"; textBox2.Text = textBox2.Name; } ]]> </x:Code> </Window> 运行结果是: 我用XAML定义了三个UI元素,其中两个TextBox是有Name的。凡是你在XAML代码里设置了它的Name,那么在C#代码里就会有一个对应的变量。这可也很好解释,看看IL程序集就知道了—— 不难看出,XAML解析器会为XAML代码中设置了Name的元素声明同名的引用变量,而且设置Name的元素则不会有引用变量生成(不过这个元素对应的对象是存在的,并且是VisualTree/LogicalTree上的结点)。 通过上面的代码,我看可以看出,Name的作用有两个: 1. 告诉XAML解析器为设置了Name的元素声明对应的引用变量(本例中是textBox1和textBox2),变量名使用Name的值。 2. 将XAML元素对应的对象(本例中是两个TextBox的实例)的Name属性设置为Name的值。 注意,引用变量一旦声明之后名字就不能改了,但对象的Name属性仍然可以改(示例中我就把由textBox2变量引用着的实例的Name属性改成Made_in_China了。) 让我们再挖深点儿——TextBox的Name属性是从哪儿继承来的呢?查一查MSDN,原来是从FrameworkElement那儿继承来的。这个Name属性是非常重要的——如果你想在一棵“树”上查找叫某个名字的元素,调用“树根”的FindName方法就可以做到了。特别需要注意的是——FindName所使用的参数是对象Name属性的值而不是引用着这个对象的变量的名字。如果你的程序里只在XAML里设置了一次Name,那么引用变量的名字和对象Name属性的值恰好一样。但如果你改变了对象Name属性的值,那可就要小心了!请看下面的代码: <Window x:Class="WpfApplication2.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="100" Width="300" Background="SteelBlue"> <StackPanel> <TextBox Name="textBox1"/> <TextBox Name="textBox2"/> <Button Content="Show Name" Click="Button_Click"/> </StackPanel> <x:Code> <![CDATA[ private void Button_Click(object sender, RoutedEventArgs e)