小序:
 
如果想用Google搜包含冒号的内容怎么办?比如我想搜x:Name这个字符串……
原来,应该是这样——x::Name
这世道,连搜索也要加转义,全民程序员,要不要人活了?
 
正文:
 
从第一天学习XAML语言开始,我就一直没分清为什么对于一个XAML标签既可以设置它的Name又可以设置它的x:Name。问过一些同事,大家好像对这种比较孔乙己的问题不太感兴趣。今天花了些时间看了看,收获还挺多的。与大家分享一下。
 
首先,让我们剖析一下XAML代码与C#代码之间的关系。
 
大家都知道,XAML是“用来设计UI”的,设计师用XAML设计出来的UI其后台代码(程序逻辑)可以由程序员用C#或者VB去写——这叫做Code-behind。实际上,设计师用XAML和程序用C#都是在构建同一个类,换句话说就是:把一个类劈成两半,与UI相关的那半由设计师用XAML写,与逻辑相关的那半由程序员用C#写。
 
.NET之所以支持这种劈开写的功能,得益于partial这个关键字。请大家看这两段代码
 
  1. // For UI
  2. public partial class Car
  3. {
  4. Color bodyColor;
  5. Color windowColor;
  6. Polygon door;
  7. Polygon seat;
  8. }
  9. // For logic
  10. public partial class Car
  11. {
  12. public void Accelerate() { /*80, 90... 120, 140....1200...flying...*/}
  13. public void Break() {/*zizizizizizizizizi....*/ }
  14. }
  1. public  class Car
  2. {
  3. // UI
  4. Color bodyColor;
  5. Color windowColor;
  6. Polygon door;
  7. Polygon seat;
  8. // logic
  9. public void Accelerate() { /*80, 90... 120, 140....1200...flying...*/}
  10. public void Break() {/*zizizizizizizizizi....*/ }
  11. }
实际效果是完全一样的。只是前者是把UI和逻辑劈开写,后者是混在一起写罢了。
 
劈开的确是劈开了,但让设计师用C#代码去实现UI恐怕不现实——让Blend直接生成C#不是不可能是事情,只是C#描述UI太不直观了。于是,微软更进一步,把界面描述语言又向设计师方向推进了一层,也就是XAML语言。于是,开发和设计的格局就变成了这样:
 
 
有了XAML和将XAML解析为C#/VB的解析器,设计师们就能以自己最高的工作效率与程序员们合作开发软件了。目前关于XAML是如何解析成C#/VB的资料非常少。
 
 
Name揭秘
 
下面让我们把目光集中在XAML->C#的解析上来,看看Name和x:Name的本质是什么。
 
让我们看一段代码:
 
  1. <Window x:Class="WpfApplication2.Window1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="Window1" Height="100" Width="300" Background="SteelBlue">
  5. <StackPanel>
  6. <TextBox Name="textBox1"/>
  7. <TextBox Name="textBox2"/>
  8. <Button Content="Show Name" Click="Button_Click"/>
  9. </StackPanel>
  10. <x:Code>
  11. <![CDATA[
  12. private void Button_Click(object sender, RoutedEventArgs e)
  13. {
  14. Button btn = e.OriginalSource as Button;
  15. textBox1.Text = btn.Name;
  16. textBox2.Name = "Made_in_China";
  17. textBox2.Text = textBox2.Name;
  18. }
  19. ]]>
  20. </x:Code>
  21. </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属性的值,那可就要小心了!请看下面的代码:
 
  1. <Window x:Class="WpfApplication2.Window1"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="Window1" Height="100" Width="300" Background="SteelBlue">
  5.     <StackPanel>
  6.         <TextBox Name="textBox1"/>
  7.         <TextBox Name="textBox2"/>
  8.         <Button Content="Show Name" Click="Button_Click"/>
  9.     </StackPanel>
  10.     <x:Code>
  11.         <![CDATA[
  12.        
  13.         private void Button_Click(object sender, RoutedEventArgs e)
  14.         {
  15.             textBox2.Name = "Made_in_China";
  16.             //this.RegisterName("Made_in_China", this.textBox2);
  17.             TextBox t = this.FindName("Made_in_China") as TextBox;
  18.             if(t==null)
  19.             {
  20.               return;
  21.             }
  22.             else
  23.             {
  24.               MessageBox.Show("OK");
  25.             }
  26.         }
  27.      
  28.         ]]>
  29.     </x:Code>
  30. </Window>
注意,除非我取消对第17行的注释,不然,尽管我已经把textBox2.Name改成了Made_in_China,但由于这个新名字还没有被注册(即没有使用RegisterName方法将Made_in_China和textBox2所引用的对象关联起来),我们仍然不能通过FindName找到它。
 
我知道这段话挺拗口,不过有一点你想通过某种方法查找由DataTemplate自动生成的UI元素时,或许应该跑来读一读这段绕口令:P
 
最后再啰嗦一句:为什么这个Name属性可以起到在运行时被当作查找标识呢?是因为FrameworkElement被一个名为RuntimeNamePropertyAttribute的attribute所修饰。这个attribute明确指定,FrameworkElement的Name属性具备了作为查找标识的资格。TextBox等类派生自FrameworkElement,自然也有这个功能。下面是FrameworkElement类的声明。
 
  1. [RuntimeNamePropertyAttribute("Name")]
  2. [StyleTypedPropertyAttribute(Property = "FocusVisualStyle", StyleTargetType = typeof(Control))]
  3. [XmlLangPropertyAttribute("Language")]
  4. public class FrameworkElement : UIElement,
  5. IFrameworkInputElement, IInputElement, ISupportInitialize
  6. {
  7. //...
  8. }
x:Name揭秘
 
x:Name的x加一个冒号,说明它来自x这个名称空间。这个名称空间是定义在XAML的根元素上的。也就是这句:
 
这个x就是XAML的字头了。这个名称空间的本意就是告诉我们——这个名称空间里所装的元素都与XAML解析有关。比如,我在代码里还使用了x:Code,把本来应该呆在C#代码里的内容请到XAML里来了。
 
可见,x:Name与Name根本不是一个层面上的东西——Name是直接与元素和面向对象编程相关的东西;x:Name是XAML语言解析层面上的东西。
 
如果我们把上面代码中的所有Name都改成x:Name,所有效果都是一样的。
不知道XAML中标有x:的内容是不是会被“预处理”一下。
 
Name与x:Name关系揭秘
 
不过,如果你的逻辑感比较强,你会发现这样一个问题——为一个XAML元素声明对应的引用变量,这不是面向对象编程层面的东西而是XAML解析层的东西。而且,如果Name在语义学上“恪守本分”的话,它应该只去设置一下对象的Name属性值而不去管是不是声明变量的事儿。
 
大胆设想一下,你会猜到,当XAML解析器发现一个元素的Name被设置了,就会去调用x:Name的那套机制。也就是说,引用变量是在x:Name机制被调用的时候声明的。同样,如果你设置的是元素的x:Name,XAML解析器会在声明变量之后再去给实例的Name属性设置值。
 
这样的猜想能够得到证实吗?让我们在MSDN里搜刮一下。
 
在x:Name的注释里,我们能找到这段话:
 
Under the standard build configuration for a WPF application project that uses XAML, partial classes, and code-behind, the specified x:Name becomes the name of a field that is created in the underlying code when XAML is processed, and that field holds a reference to the object.
 
而在FrameworkElement.Name属性的文档里,又能找到这句话:
 
This property essentially provides a WPF framework-level convenience property to set the XAML x:Name Attribute.
 
也就是说,Name的确会去调x:Name那套机制。为什么这么做?可能是为了写起来方便。不过,我真不太喜欢这种搅和在一起的风格。我宁可使用Name去给对象的Name属性赋值而使用x:Name去声明变量。
 
貌似“Under the standard build configuration ”这句话有点玄机。不知道非standard编译配置会有什么样的效果,怎样才能自定义编译配置呢?
 
不喜欢这种风格的原因还在于:Name和x:Name互相调用会在某些逻辑下出问题,特别是“先有鸡还是先有蛋”这种情况下。
 
关于在XAML中使用同一个程序集中的User Control
 
说到“先有鸡还是先有蛋”的问题,让我想起了另一个困扰自己很久的问题。请看下面的代码:
 
假设我有这样一个project,
 
 
 
现在我想把MyControl用在我的Window1里。如果代码写成这样:
 
  1. <Window x:Class="WpfApplication.Window1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:WpfApplication"
  5. Title="Window1" Height="300" Width="300">
  6. <Grid>
  7. <local:MyControl Name="myControl"/>
  8. </Grid>
  9. </Window>
当编译的时候,会报出错误:
 
 
 
 
最让人哭笑不得的原因就是“因为MyControl是在同一个程序集里,你就得使用x:Name而不是Name!”这算什么解释?跟是不是同一个程序集有什么关系?
 
TO BE CONTINUE...

本文出自 “上善若水 润物无声” 博客,请务必保留此出处http://liutiemeng.blog.51cto.com/120361/121354

Name与x:Name的关系的更多相关文章

  1. Angular2入门系列教程3-多个组件,主从关系

    上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...

  2. 死磕内存篇 --- JAVA进程和linux内存间的大小关系

    运行个JAVA 用sleep去hold住 package org.hjb.test; public class TestOnly { public static void main(String[] ...

  3. 页面中多个script块之间的关系

     一:函数声明与函数定义表达式在函数调用间的区别 <script type="text/javascript"> doA(); var doA = function(a ...

  4. Android Ormlite 学习笔记2 -- 主外键关系

    以上一篇为例子,进行主外键的查询 定义Users.java 和 Role.java Users -- Role 关系为:1对1 即父表关系 Role -- Users 关系为:1对多 即子表关系 下面 ...

  5. ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系

    ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的.如果我们将最终处理HTTP请求的组件称为HttpHandler,那么RouterMiddleware中间 ...

  6. 问题记录:EntityFramework 一对一关系映射

    EntityFramework 一对一关系映射有很多种,比如主键作为关联,配置比较简单,示例代码: public class Teacher { public int Id { get; set; } ...

  7. 代码的坏味道(19)——狎昵关系(Inappropriate Intimacy)

    坏味道--狎昵关系(Inappropriate Intimacy) 特征 一个类大量使用另一个类的内部字段和方法. 问题原因 类和类之间应该尽量少的感知彼此(减少耦合).这样的类更容易维护和复用. 解 ...

  8. UML图中经常用到几种的关系图例

    学习这个东西挺奇怪的,时间一长就容易忘记,或者记不清楚.今天看到一些UML图的关系,发现有些出入了,索性就写下来,以后再忘记的时候过来看看. 在UML的类图中,常见的有以下几种关系: 继承(Gener ...

  9. maven的pom.xml关系依赖书写顺序

    今天遇到了一个情况,以前代码编译没有问题,升级了hbase客户端phoenix驱动,又调整了thrift的关系依赖的位置,放到了这个驱动后面. 如下: 导致了一个thrift接口类编译报错: 检查这个 ...

  10. .Net 初步学习笔记之一——.Net 平台与.Net FrameWork框架的关系

    .Net 包含两部分 .Net平台 和.Net FrameWork 框架 1..Net FrameWork框架包含于.Net平台. .Net FrameWork提供环境和支撑保证.Net平台运行. 2 ...

随机推荐

  1. 【树形dp】Distance in Tree

    [CF161.D] Distance in Tree time limit per test 3 seconds memory limit per test 512 megabytes A tree  ...

  2. 【推导】Codeforces Round #364 (Div. 2) D. As Fast As Possible

    一种方法是二分总时间,复杂度O(nlogn). 另外我们可以证明,当所有人同时到达终点的时候,是最优的,因为没有人的时间“浪费”了. 我们又发现,每个人的运动过程总是两段,要么是走路,要么是坐车.于是 ...

  3. 【AC自动机】HDU中模板题

    [HDU2222] 最纯粹的裸题,错误点详见注释. #include<iostream> #include<cstdio> #include<cstring> #i ...

  4. 2.1(java编程思想笔记)位移操作

    java位移操作主要有两种: 有符号位移:有符号位移会保留原有数字正负性,即正数依然是正数,负数依然是负数. 有符号位左移时,低位补0. 有符号右移时:当数字为正数,高位补0.当数字为负时高位补1. ...

  5. React中的表单元素

    在web应用开发当中,表单还是很重要的元素. 应用表单组件有:文本框(input.textarea).单选按钮和复选框.Select组件. 文本框:文本框的状态改变即文本框中的内容的改变.此时的sta ...

  6. BZOJ 4029: [HEOI2015]定价 贪心

    4029: [HEOI2015]定价 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4029 Description 在市场上有很多商品的 ...

  7. (转) Unity3D常用代码收集总结

    //创建一个名为"Player"的游戏物体 //并给他添加刚体和立方体碰撞器. player=new GameObject("Player"); player. ...

  8. php函数前面加&符号 和 变量前面加&符号的意义

    php函数前面加&符号 和 变量前面加&符号的意义 php函数前面加&符号的意思是函数的引用返回,php函数前面加&符号有什么作用呢 function &tes ...

  9. .net设置中GridView自适应列宽

    有一个项目只有30分钟开发时间,速成,使用了古老的.net gridview. 但需要列宽自适应好看些. 于是琢磨了,实现思路如下. 先看下大致效果(很粗暴没有优化) 代码如下: protected ...

  10. [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】

    YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出[高危] 问题描述: YS VTM模块开放对外监听端口(8554和8664),此次使用sulley fuzzing框架对监听在8664端口 ...