代码改变世界

Window Presentation Foundation系列 (1)---从HelloWorld认知WPF

2011-06-21 17:22  libiver  阅读(500)  评论(0编辑  收藏  举报

       声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 

       本文链接:http://www.cnblogs.com/leezhm/archive/2011/06/21/2086239.html

       开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 的Blog

       Ok,作为一个Programmer,绝大部分人对一种全新的语言的第一个程序应该都是Hello,World吧。在这里我也从这个开始,一个最简单的Hello World。代码如下:

    1: using System;
   2: using System.Windows;
   3:  
   4: namespace HelloWorld
   5: {
   6:     class HelloWorld
   7:     {    
   8:         [STAThread]
   9:         public static void Main(string [] args)
  10:         {
  11:             //Console.WriteLine("Hello, World! This is a most simple WPF Application");
  12:         }
  13:     }
  14: }

     

      使用命令行编译,如下 csc /out:.\HelloWorld.exe HelloWorld.cs。编译成功运行,运行会显示Hello, World! This is a simple WPF Application的一个消息。但是这个WPF很不完整,没有使用任何的WPF服务,也可以说跟WPF扯不上关系,它只是一个简单的C# Console程序。到底真正的WPF包含哪些关键的组件(或者核心的DLL文件)以及WPF能够做些什么?我们可以通过下面的图片来理解.

WPF1

图 1

      上图中标为暗红色的是WPF的三大核心组件,其中milcore组件,它的职责是完成与Direct3D的交互。并且出于效率和安全考虑,milcore由非托管代码实现。WPF 中的所有显示是通过 DirectX 引擎完成的,可实现高效的硬件和软件呈现。WPF 还要求对内存和线程执行进行精确控制。milcore 中的组合引擎受性能影响关系大,需要放弃 CLR 的许多优点来提高性能。WPF的另外两大核心组件PresentationFramework和PresentationCore都位于通用语言运行库(CLR)之上。而那么就可以看出,WPF的大部分代码都是以托管形式存在的。这两大组件提供了WPF项目需要的函数库和功能库,由于是以托管的形式存在,所以也避免了我们直接操作底层和出现诸如内存泄露的可能性。

                                      

          图  2   

      从上面的这幅图可以看出一共分成了五大块(Core Presentation、User Interface Services、Base Services、Document Servies和XPS Viewer):

  • Core Presentation:包含了所有的图形效果,如图形、2D图形、3D图形、文本、音频、视频和显示效果。同时还包括强大的动画效果,动画可以应用前面的所有元素。最下面的那个就是视觉基本元素。
  • User Interface Services:包含了应用程序服务、部署服务、控件库、布局和数据绑定.
  • Base Services:提供了XAML支持、提高开发效率、输入和事件的支持、属性系统。
  • Document Servies和XPS Viewer则提供了基本的打印和表报服务,可以通过这些组件实现自定义的打印和显示效果。

      好了,再继续改进Hello World,改进后的代码如下:

   1: using System;
   2: using System.Windows;
   3: namespace HelloWorld
   4: {
   5:     [STAThread]
   6:     public static void Main(string [] args)
   7:     {
   8:         //MessageBox.Show("Hello, World! This is a simple WPF Application");
   9:         
  10:         Window wnd = new Window();  
  11:         wnd.Width = 800;  
  12:         wnd.Height = 600;  
  13:         wnd.Title = "Hello World";  
  14:         wnd.Show();  
  15:           
  16:         Application app = new Application();  
  17:         app.Run(); 
  18:     }
  19: }

           再次通过命令行编译,编译命令如下(这里为了便于理解,我对编译命令做了排版,实际使用中并不需要这样)

 

   1:  csc  /target:winexe /out:.\HelloWorld.exe
   2:   
   3:  /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationframework.dll"
   4:   
   5:  /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\windowsbase.dll"
   6:   
   7:  /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationcore.dll"
   8:   
   9:  HelloWorld.cs

   

           注意,在这里引用了prensentationframework.dll、presentationcore.dll和windowsbase.dll这三个WPF的核心DLL。在这里使用.net Reflector(http://reflectoraddins.codeplex.com/)来查看编译后的exe文件的IL代码如下:          

    图  3

          

          由上图,我们可以清楚地看出来,WPF程序的编译过程,并且可以看到它链接了那些WPF组件。

          当然,一个真正的WPF程序远不止一个消息对话框或者一个简单的什么都没有的窗体而已,它是需要有Application类的实例。在这里我们来分别继承一个Application和Windows,具体代码如下:

   1:  using System;  
   2:  using System.Windows;  
   3:  namespace HelloWorld  
   4:  {  
   5:      class HelloWorld : Application  
   6:      {  
   7:          [STAThread]  
   8:          public static void Main(string [] args)  
   9:          {  
  10:      /*      #region // simple I 
  11:              MessageBox.Show("Hello, World! This is a simple WPF Application"); 
  12:              #endregion // simple I 
  13:               
  14:              #region // simple II 
  15:              Window wnd = new Window(); 
  16:              wnd.Width = 800; 
  17:              wnd.Height = 600; 
  18:              wnd.Title = "Hello World"; 
  19:              wnd.Show(); 
  20:               
  21:              Application app = new Application(); 
  22:              app.Run(); 
  23:              #endregion // simple II 
  24:      */        
  25:              #region // simple III  
  26:              HelloWorldWnd wnd = new HelloWorldWnd();  
  27:              wnd.Show();  
  28:                
  29:              HelloWorld helloWorld = new HelloWorld();  
  30:              helloWorld.Run();  
  31:              #endregion // simple III  
  32:          }  
  33:      }  
  34:        
  35:      class HelloWorldWnd : Window  
  36:      {  
  37:          public HelloWorldWnd()  
  38:          {  
  39:              this.Width = 400;  
  40:              this.Height = 300;  
  41:              this.Title = "Hello World Windows";  
  42:          }  
  43:      }  
  44:  }  
 
       同样使用Reflector来查看IL代码,如下所示:
图  4

图 5

 

       上两图分别是从Application继承的类HelloWorld和从Window继承的HelloWorldWnd类的IL代码,比较图3,基本上是一样的过程,只不过分别是俩个类而已。

 

       不过通过最后的HelloWorld和HelloWorldWnd类,我们可以看出来,其实可以将WPF的代码分隔开来,HelloWorld里面实现了WPF的“行为”;而HelloWorldWnd则实现了WPF的“外观”。这样我们就可以分别将注意力放在不同的事情上,比如设计师可以专注于UI设计,而软件工程师则可以专注于程序的逻辑处理。好了,如果我们为WPF的“外观”的代码定义一种声明式的格式,并且这种格式的文件可以通过工具拖拽等方式来创建,那就Perfect了。是不是描述的有点像flex啊,好了其实我们是幸运的,MS为我们实现了这些。具体的在WPF中表现为XAML格式。用XAML来实现HelloWorldWnd类的代码如下:

 

   1:  <!-- HelloWorldWindow.axml -->  
   2:  <Window x:Class = "HelloWorld.HelloWorldWnd"  
   3:          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
   4:          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
   5:          Title="Hello World Windows"  
   6:          Width="400" Height="300">  
   7:  </Window>  

 

       其实很简单的,一种声明式的语法,简单地描述了这个windows的特征。XAML的规范定义了一些规则,来把.Net的命名空间、类型、属性、事件等一系列元素映射成XAML的命名空间、元素和特征。XAML被尽可能地设计成直接映射,比如一个XAML元素就映射一个.Net的类名,一个XAML属性(Attribute)就映射成相应类的属性(Property)名或者类的相应的事件名。这样XAML不仅仅只能为WPF类所用,还可以让有默认构造函数的.Net的类可以在XAML文件中直接完成初始化。比如上面的Window类

 

       好了,我们看看Visual Studio .Net 2010创建的一个WPF Application项目的结构图,截图如下:

                                                                                                        图 6

      从图6中标准WPF程序结构图可以看出,WPF需要PresentationCore、PresentationFramework和WIndowsBase这三个核心的组件的支持;XAML和Code-behind文件的关系;关键字partial在WPF中的作用。

 

      代码隐藏(code-behind)文件的扩展名为.xaml.cs,它包含了xaml中未定义的部分,通过关键字partial让编译器把它和xaml定义合成一个完整的类定义。一般在代码隐藏文件中实现类的一“行为”处理,比如元素是事件等。

 

      通过上面的例子,大概了解清楚了WPF程序的基本框架,当然一些具体的细节,需要自己具体去查询MSDN等资料。