2011年7月16日
很不错的文章,相信很多人都被这个问题困扰过
以下内容转载自http://blog.csdn.net/FantasiaX/article/details/3499767,版权归作者所有
杂七杂八——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这个关键字。请大家看这两段代码
- public partial class Car
- {
- Color bodyColor;
- Color windowColor;
- Polygon door;
- Polygon seat;
- }
- public partial class Car
- {
- public void Accelerate() { }
- public void Break() { }
- }
- public class Car
- {
- Color bodyColor;
- Color windowColor;
- Polygon door;
- Polygon seat;
- public void Accelerate() { }
- public void Break() { }
- }
实际效果是完全一样的。只是前者是把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)
- {
- textBox2.Name = "Made_in_China";
- TextBox t = this.FindName("Made_in_China") as TextBox;
- if(t==null)
- {
- return;
- }
- else
- {
- MessageBox.Show("OK");
- }
- }
- ]]>
- </x:Code>
- </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类的声明。
- [RuntimeNamePropertyAttribute("Name")]
- [StyleTypedPropertyAttribute(Property = "FocusVisualStyle", StyleTargetType = typeof(Control))]
- [XmlLangPropertyAttribute("Language")]
- public class FrameworkElement : UIElement,
- IFrameworkInputElement, IInputElement, ISupportInitialize
- {
- }
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里。如果代码写成这样:
- <Window x:Class="WpfApplication.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WpfApplication"
- Title="Window1" Height="300" Width="300">
- <Grid>
- <local:MyControl Name="myControl"/>
- </Grid>
- </Window>
当编译的时候,会报出错误:
最让人哭笑不得的原因就是“因为MyControl是在同一个程序集里,你就得使用x:Name而不是Name!”这算什么解释?跟是不是同一个程序集有什么关系?
=====================================
崔维福的补充:
"跟是不是同一个程序集有什么关系" 具体来说还是有关系的。你一定知道Name不能和x:Name同时用,因为在build的时候他知道这两个做了相同的工作,什么工作呢,就是做在“类名.g.cs”,中添加了后台代码,x:Name是Attribute,而Name是DP,编译器可以挖掘Attribute来为自己的后台添加内容,但是不能用Name来添加,因为自己还没有被构造完全呢。所以呢就是告诉你,要用x:Name,要不就把这个contro放到别的project下,它好能把它构造出来!希望我解释的够清楚!
作者:
感谢崔先生的批注,您对技术精益求精的精神让我非常景仰,向您学习、致敬!
=====================================
TO BE CONTINUE...
2011年7月9日
近几天来,突然发现实验室电脑的显示器总是过一分钟就“自动关闭”,本能的检查了电源选项里的“关闭显示器的时间”,所有的电源计划中的该项设置都是“从不”,但是显示器还是一如既往的“自动关闭”,于是开始怀疑是不是Windows本身的问题,但刚刚突然想起“一分钟”这个特殊的时间,通常是触发“屏幕保护程序”的默认时间值,于是赶紧查看屏保设置,果然,屏保被设置为了“空白”(实际效果就是屏幕变黑)。于是想起几天前尝试过Windows 8 Metro 主题,估计是自动重置了屏保。
问题不大,但是却有些蹊跷,只是想说,人很多时候对现象的理解都是基于自己的知识结构和经验的,遇到貌似无解的问题是,抛开现有的想法,也许答案就是那么简单。
2011年6月16日
2010年10月2日
最近需要基于UG(现在叫NX)做一些开发。由于用Windows7 +VS2010已经有一段时间了,感觉还不错,于是为了不重新折腾开发环境,下载安装了能够支持Windows7的UG最新版本NX7.5。安装过程与之前版本没有区别,但是在配置NXOpen for C++(详细介绍请看begtostudy的博客)时才发现,如果注定要折腾,那只是迟早的事。
由于NXOpen几乎为UG的所有功能都提供了接口,因此规模可见一斑。为了方便开发,NXOpen提供了Visual Studio中常见的Wizard来帮助开发者快速创建所需的项目类型,免去手动添加头文件、链接库等配置的麻烦。然后,即使最新的NX7.5,所提供的Wizard也只支持到VS2008。如果直接按照文档中的安装说明,将Wizard相关文件拷贝到VS的对应目录下的话,Wizard并不会出现在新建项目的菜单中,玄机在NX7_Open.vsz这个文件中,这个文件保存了Wizard的基本信息,内容如下:
1VSWIZARD 7.0
2Wizard=VsWizard.VsWizardEngine.9.0
3
4Param="WIZARD_NAME = NX7_Open"
5Param="FALLBACK_LCID = 1033"
第2行中,默认的VsWizardEngine版本是9.0(VS2008),因此需要手动改为10.0(VS2010)。修改保存后,启动VS2010,在新建菜单的C++类别下,就可以看到NX7 Open Wizard的选项了,但是问题到此还没有结束(我正是从这里开始折腾的)。选择NX7 Open Wizard,确定后会弹出类似于MFC中的新建项目向导,提供一些配置(不需要修改的话可以直接点Finish)。但是当点击Finish的时候,问题出现了,错误信息为“对象不支持此操作”,项目创建失败。初次看到这样的错误提示,的确无从下手,但是任何错误都一定有原因的。
Visual Studio中的项目模板和向导都是可以自定义的,并且在VS2010中还提供了创建自定义Wizard的项目模板Custom Wizard(详细的资料看这里)。根据MSDN上的相关内容介绍,Wizard其实是一组html页面(每个页面对应一个步骤),通过JScript来调用Visual Studio提供的内建对象(code, project 和wizard)来实现最终项目的生成和配置。每一个Wizard项目都会包含一些固定的文件和文件夹,如下(来自MSDN):
File
|
Description
|
Project.vsz
|
A text file that resembles the old .ini format. It identifies the wizard engine and provides context and optional custom parameters.
|
Project.vsdir
|
A text file that enables the Visual Studio shell to find the wizard and display it in the New Project dialog box.
|
HTML files (optional)
|
A wizard can contain a user interface (UI), which is an HTML interface. A wizard without a UI contains no HTML files.
If a wizard has a UI, each individual screen in the wizard is known as a page, and each page specifies UI features.
The default.htm file defines the first page in the wizard. Use the Number of pages list box of Application Settings, Custom Wizard to specify additional pages. Each additional page is defined by a Page_page-number.htm file, where page-number ranges from 2 through the number of pages that you specify.
|
Script files
|
The Custom Wizard creates a JScript file, default.js, for each wizard created. This file contains JScript functions that access the Visual C++ Wizard, Code, and Environment Object Models to customize a wizard. You can customize and add functions in your wizard's default.js file.
Additionally, your wizard includes the common.js file, which contains commonly used JScript functions and is shared among all wizards, including the wizards used by Visual C++ to create other project types. For more information, see Customizing C++ Wizards with Common JScript Functions.
|
Templates
|
A wizard's templates are a collection of text files that contain directives, which are parsed and inserted into the symbol table, depending on the wizard user's selections. The template text files are rendered according to the user input and added to the project created by the wizard. The appropriate information is obtained by directly accessing the wizard control's symbol table.
|
Templates.inf
|
A text file that lists all templates associated with the project.
|
Default.vcxproj
|
An .xml file that contains the information about the project type.
|
Sample.txt
|
A template file that shows how your wizard directives are used.
|
ReadMe.txt
|
A template file that contains a summary of each file created by the Custom Wizard.
|
Images (optional)
|
You can provide any images, such as icons, GIFs, BMPs, and other HTML-supported image formats, to enhance the UI for your wizard. A wizard that has no UI does not require images.
|
Styles.css (optional)
|
A file that defines the styles for the UI. If your wizard does not have a user interface, the Custom Wizard does not create a .css file.
|
其中提到的Script Files(默认为default.js)完成了项目生成的主要工作,而之前提到的错误也正出在这里。CustomWizard项目中的html files需要调用Visual Studio提供的内建对象(包含在common.js中),因此没有办法想调试网页一样使用浏览器调试JScript脚本,VS2010貌似也没有提供其他的调试JScript的方法(至少我没有找到),因此不得不利用注释测试NX7_Open中default.js的每一行语句(好在文件不是很长),最后终于发现了罪魁祸首,在default.js文件的第200行:
200 CLTool.Detect64BitPortabilityProblems = true;
这句的作用是设置一个编译器开关,指定编译器在编译过程中检查程序的64位可移植性,但是在VS2010,这一特性在VS2010中已经不建议使用,并且这种设置方式已经不适用于VS2010(详见
这里),所以才出现错误信息“对象不支持此操作”,解决办法很简单,直接注释掉该行就可以了。至此,就可以愉快的在VS2010中使用NX7 Open Wizard创建你自己的项目了。
尽管问题很简单,解决办法也很简单,但探索的过程是漫长的,好在国庆长假时间充裕。最后再次感谢begtostudy学长(虽然彼此不认识)的博客。
2007年9月5日
摘要: 位操作
为操作有两种方式,C风格以及C++风格。
1. C风格的位操作使用了一系列的位操作运算符,如下:
操作符
功能
...
阅读全文
2007年9月2日
前些天在网上搜罗了些C++的经典书籍,大多是.chm格式的。刚刚有空,想拿来读读,可是郁闷的事情发生了,点击目录时,右面竟然显示“该页无法显示”!
郁闷,下的时候还好好的,怎么现在就down了呢?难道是病毒?
百度了问题之后,发现答案前篇一律:
一.
1、开始运行,输入:regsvr32 C:\windows\system32\hhctrl.ocx ,确定,重新关联文件。
2、执行一下windows目录里的hh.exe 。
二.
1. 在微软网站上下载hhupd.exe,安装hh.exe后并运行。
2.实际上,下载hhupd.exe后,运行后就可以了。这个东西大小为461kb 3.在c:\windows\system32里找到“Hhctrl.ocx”文件,然后运行:“regsvr32 c:\windows\system32\hhctrl.ocx...
三
1,右键关联chm文件的“打开方式”到\Windows\HH.exe
2,在命令行运行regsvr32 itss.dll
3,在命令行运行regsvr32 hhctrl.ocx
但这些方法我对我却丝毫不起作用,于是只能自寻出路。我试着把某个文件copy到桌面上,试着打开,居然成功了。直觉告诉我,问题出在文件夹的名称上。因为我突然想起自己在整理之后把目录名称改成了"C__C++__C#”,于是试探性的更改了文件夹名称,试了几次,终于确定了罪魁祸首——是“#”。把"C#”改成"C Sharp"以后,问题解决了。
那究竟为什有了"#"就不行了呢?因为.chm是以html格式存储内容的,所以每一页都对应了一个本地的URL地址。在URL地址的标准规定中"#"是属于特殊字符,代表书签,详细的标准说明可以参看这里http://www.128kj.com/article/article9/D15BCF6C477EAA03699B8B9FB25B3CD9.htm?id=675。
如果目录名称里含有"#"或者其他特殊字符的话,URL地址就因此而被中断了,自然“该页无法显示”。
Notes on C++ Primer
(一)
文字常量
1. 整数文字常量可以被写成十进制八进制或者十六进制的形式这不会改变该整数值的
位序列。
2. 在整型文字常量前面加一个0, 该值将被解释成一个八进制数而在前面加一个0x 或0X
则会使一个整型文字常量被解释成十六进制数。
3.整型文字常量默认为有有符号的int类型,可以在常量后添加“L/l”将常量指定为long类型,添加“U/u”来将常量指定为无符号类型。例如1024L、222U。
4.浮点类型的文字常量可表示为普通十进制或者科学计数法,例如:25.3、2.7E2。在普通十进制表示时,可以在常量后追加“F/f”将常量指定为单精度,“L/l”扩展精度。
5.一部分不可打印的字符单引号双引号以及反斜杠可以用如下的转义序列来表示,转义符的基本格式为:\xxx(xxx为三位的八进制数)。下表为各转义符的意义。
newline(换行符) \n
horizontal tab(水平制表键) \t
vertical tab(垂直制表键) \v
backspace(退格键) \b
carriage return (回车键) \r
formfeed (进纸键) \f
alert (beel) (响铃符) \a
backslash (反斜杠键) \\
question mark (问号) \?
single quote (单引号) \'
double quote (双引号) \"
6.字符型常量默认为char类型,可以通在常量前面加上“L”将常量指定为w_char宽字符类型。同样也可以将char类型的字符串指定为宽字符串。
注意:C++会自动将程序中的相邻两个普通字符串或宽字符串连接成一个,而当普通字符串与宽字符串相邻时,则会出错!
变量
1. 变量命名习惯。
通常变量名用小心字母,如index。而Index则通常作为类名,INDEX则通常被定义为常量(用#DEFINE)定义。在包含有多个单词的变量命中,习惯上在每个词间加下划线“_”或者每个词首字母大写。
2. L-Value & R-Value
L-Value可解释为“Left Value”或者“Location Value”,用于储存内存地址。而R-Value可解释为“Right-Value”或者“Read Value”,用于储存用户数据。
指针
1. 指针定义时的“*”与解引用符“*”是两个不同的概念。定义时的*代表之后的变量是某类型的指针,而解引用符与变量名共同组成一个等同于改类型变量的符号。更确切的说,在定义时,*是与类型名组合,而解引用时,*是与变量名组合。
字符串
1. c风格的字符串,以字符数组的方式声明,操作与普通数组基本相同,唯一的不同是字符数组支持整体输出,以及包含在 “cstring.h” 中的一些函数。
2. c++字符串类型,是标准库中的一个类。与c风格的字符串相比,后者的最大好处是避免了前者对字符的底层操作而引起的错误,增加了程序的稳定性与速度。
注意:二者均属于c++标准库中的部分。
CONST修饰符
1. 将一个常量定义为变量:Const <类型名> <变量名>
2. 指向常量变量的指针:const <类型名> * <变量名>。指针本身的值是可以赋值或者修改的,而指针所指向的对象的值不可修改。
3. 常量指针:<类型名> * const <变量名>。指针指向的内容可以被修改,但指针本身不可以被赋值其他地址。
小结:const修饰符总是将限定作用加在最靠近他的那个关键字上,类似于英语语法中的就近原则。
枚举类型
1. 枚举类型定义了一个自定义属性的集合:enum <集合名> {元素1,元素2,……}
2. 枚举类型的元素可以在定义时被赋予整形值,可以比较大小及其他运算,但是只可以利用同类型的变量对已有变量赋值。
数组
数组与指针的关系:数组名是以个指向数组元素类型的指针,因此,理论上可以用指针完全操作数组。
数组的代替:vector
C++标准库提供了更易于使用的数组替代品Vector(当然,某些特殊的情况依然需要内置数组),使用Vector需要包含头文件“vector”。
与内置数组相比,标准vector类提供了很多便利的函数,比如empty(),size(),begin(),end()等。
Typedef
Typedef定义了一个类型的别名,而不是一个新类。换句话说,tyepdef定义的名称与已有的完整的类名有完全相同的功能。Typedef并不支持在类基础上的任何自定义操作。
Volatile
当一个对象的值可能会在编译器的控制或监测之外被改变时,例如一个被系统时钟更新
的变量,那么该对象应该声明成volatile。 因此编译器执行的某些例行优化行为不能应用在
已指定为volatile 的对象上。
注意:volatile与const一样,都是类型的附加修饰符。
Pair类型
pair类型也是C++标准库的一部分,包含在头文件“utility”中。定义方式如下:
pair <type1,type2>
它使得变量能够将两个不同的类型联合起来。
2007年8月28日
#DEFINE NOW 2007.8.28
#DEFINE FUN 0
#include "interest"
#include "passion"
#include "patience"
using namespace Life;
void main()
{
interest MyInterest;
passion MyPassion;
patience MyPatience;
int day=NOW
do
{
Myinterest.Up();
MyPassion.Up();
MyPatience.Up();
day++;
}while (day>1000000)
return FUN;
}