杂七杂八——Name与x:Name的关系

简介:

杂七杂八——Name与x:Name的关系

 

小序:

 

 如果想用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.        
  12.      
  13.        private void Button_Click(object sender, RoutedEventArgs e)
  14.        {
  15.            Button btn = e.OriginalSource as Button;
  16.            textBox1.Text = btn.Name;

  17.            textBox2.Name = "Made_in_China";
  18.            textBox2.Text = textBox2.Name;
  19.        }
  20.    
  21.        ]]>
  22.    x:Code>
  23. 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. "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.    
  6.        "textBox1"/>
  7.        "textBox2"/>
  8.        "Show Name" Click="Button_Click"/>
  9.    

  10.    
  11.        
  12.  
  13.      
  14.        private void Button_Click(object sender, RoutedEventArgs e)
  15.        {
  16.            textBox2.Name = "Made_in_China";
  17.            //this.RegisterName("Made_in_China", this.textBox2);
  18.            TextBox t = this.FindName("Made_in_China") as TextBox;
  19.            if(t==null)
  20.            {
  21.              return;
  22.            }
  23.            else
  24.            {
  25.              MessageBox.Show("OK");
  26.            }
  27.        }
  28.    
  29.        ]]>
  30.    

  31.  

注意,除非我取消对第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的根元素上的。也就是这句:  

 

  1. xmlns:x=[url]http://schemas.microsoft.com/winfx/2006/xaml[/url]

 这个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. "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.    
  7.        "myControl"/>
  8.    


 当编译的时候,会报出错误:  

 

 

 

 

 最让人哭笑不得的原因就是“因为MyControl是在同一个程序集里,你就得使用x:Name而不是Name!”这算什么解释?跟是不是同一个程序集有什么关系?  

 

 TO BE CONTINUE...  










本文转自 水之真谛 51CTO博客,原文链接:http://blog.51cto.com/liutiemeng/121354,如需转载请自行联系原作者

目录
相关文章
|
3天前
|
搜索推荐 编译器 Linux
一个可用于企业开发及通用跨平台的Makefile文件
一款适用于企业级开发的通用跨平台Makefile,支持C/C++混合编译、多目标输出(可执行文件、静态/动态库)、Release/Debug版本管理。配置简洁,仅需修改带`MF_CONFIGURE_`前缀的变量,支持脚本化配置与子Makefile管理,具备完善日志、错误提示和跨平台兼容性,附详细文档与示例,便于学习与集成。
271 116
|
18天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
12天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
663 219
|
5天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
349 34
Meta SAM3开源:让图像分割,听懂你的话
|
10天前
|
人工智能 移动开发 自然语言处理
2025最新HTML静态网页制作工具推荐:10款免费在线生成器小白也能5分钟上手
晓猛团队精选2025年10款真正免费、无需编程的在线HTML建站工具,涵盖AI生成、拖拽编辑、设计稿转代码等多种类型,均支持浏览器直接使用、快速出图与文件导出,特别适合零基础用户快速搭建个人网站、落地页或企业官网。
1562 157
|
存储 人工智能 监控
从代码生成到自主决策:打造一个Coding驱动的“自我编程”Agent
本文介绍了一种基于LLM的“自我编程”Agent系统,通过代码驱动实现复杂逻辑。该Agent以Python为执行引擎,结合Py4j实现Java与Python交互,支持多工具调用、记忆分层与上下文工程,具备感知、认知、表达、自我评估等能力模块,目标是打造可进化的“1.5线”智能助手。
897 61
|
7天前
|
编解码 Linux 数据安全/隐私保护
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
295 140