不可错过的MSDN TV —— IronPython: Python on the .NET Framework (下)

来源:互联网 时间:1970-01-01

在去年的Post中,介绍了Demo中有关WinFX的内容。那么今年呢,我们继续把这件做了一年的事情给做完。IronPython 1.0都赶在2005年的最后一天发布了,而这个系列的最后一篇Post竟然难产,成为2006年的新生儿,也真够FT的~~
Demo 6 与C#之间的互协作:Demo中使用ImageView的Sample来自Windows SDK中WinFX SDK的部分,由于WinFX SDK并没有单独发布的,因此要把WinFX SDK安装上去还是得把整个Window SDK装上。而Windows SDK是以DVD Image的形式发布的,通常是需要刻录成DVD,或者使用解压缩工具打开的,MS也提供了一个很小巧的工具(在下载页面的Instruction部分有介绍):Virtual CD-ROM Control Panel for Windows XP帮助你创建一个虚拟DVD光驱,利用它可以轻松地打开下载的Image文件。在安装了Windows SDK之后,你可以在帮助文档中使用"ImageView Sample"作为关键字进行搜索,即可找到Demo中的ImageView这个Sample。为了能够在VS 2005正确地运行这个Sample,还得把WinFX Development Tools For VS 2005装上去。万事俱备之后,将这个Sample运行起来已经不成问题了。
Demo 6.1 在C#中执行简单的IronPython代码:运行了原装正版的WinFX ImageView Sample之后,我们接下来就要根据Demo的演示,对这个Sample进行一些小改动,增加新的功能以体现IronPython与C#之间的协作性。首先是在default.xaml中增加一个新的Button并设置Click的属性,然后在default.xaml.cs中增加相应的事件处理函数:RunScript。代码分析如下:

1. PythonEngine engine = new PythonEngine(); 创建一个PythonEngine实例,通过该实例的方法可以执行IronPython的代码;
2. engine.SetVariable("win", this); 设置IronPython代码执行所需要的变量,这段代码实质就是对应:win = this。而this指的就是ImageViewExample的实例,而ImageViewExample则是继承于System.Windows.Window类;
3. engine.Execute("win.SetImage('c:/images/itrun.jpg')"); 执行一行简单的IronPython代码:win.SetImage('c:/images/itrun.jpg')。


Demo用到了一个SetImage的方法,而这个方法在原始版本的ImageView Sample中是没有的,为了方便大家,将该方法的代码列示如下:

public void SetImage(string filename) {
Uri selLoc = new Uri(filename);
BitmapImage id = new BitmapImage(selLoc);
FileInfo currFileInfo = new FileInfo(filename);
currentImage.Source = id;

//Setup Info Text
imageSize.Text = id.PixelWidth.ToString() + " x " + id.PixelHeight.ToString();
imageFormat.Text = id.Format.ToString();
fileSize.Text = ((currFileInfo.Length + 512) / 1024).ToString() + "k";
}


好了,Demo 6的第一部分就完成了,是不是有点迷惑呢?我猜你的迷惑就在于Demo 6的title上:与C#之间的互相协作,或许你会觉得把以上内容称作C#与IronPython的协作就像是在糊弄人,因为这样的调用似乎没有什么意义,我还不如直接调用SetImage方法呢。嗯,嗯,别急,这个Demo还有第二部分哦。

Demo 6.2 将IronPython代码从C#代码中分离出来:从Demo 6.1可以看到,IronPython代码直接写在了C#代码中。很明显,这种做法只能够执行一些简单的IronPython Script,如果复杂一些的话,恐怕就会令C#代码显得凌乱了。因此IronPython Engine提供了一个RunFile的方法,让你可以将IronPython Script从C#代码中独立出来,以.py的文件存在,并在运行期调用之。这个Demo使用了类OpenFileDialog,因此需要增加对System.Windows.Forms的引用。代码分析如下:

1. using OpenFileDialog = System.Windows.Forms.OpenFileDialog; 不直接使用using System.Windows.Forms是为了防止类名冲突,因为System.Windows.Controls和System.Windows.Forms这两个Namespace都有ListBox类;
2. engine.RunFile(ofd.FileName); 调用IronPython Engine提供的RunFile方法,其中ofd为OpenFileDialog的实例。


Demo中调用了sample.py的IronPython Script,该文件的内容如下:

import sys
sys.LoadAssemblyByName("WindowsBase")
sys.LoadAssemblyByName("PresentationCore")
sys.LoadAssemblyByName("PresentationFramework")

from System import *
from System.Windows.Controls import *
from System.Windows.Media.Animation import *
from System.Windows.Media import *
from System.Windows import *
from System.Windows.Shapes import *

text = TextBlock(Text='MSDN Rocks', FontSize=100, Foreground = Brushes.Black)
a = DoubleAnimation(0.0, Duration(TimeSpan.FromSeconds(3)))
text.BeginAnimation(Shape.OpacityProperty, a)
Canvas.SetLeft(text, 5)
Canvas.SetTop(text, 15) #以上两行有关Canvas的设置其实是无效的,因为XAML中并没有canvas的定义

win.Content.Children[1].Children.Add(text)


启动这个Demo之后,不要选择图片,而是直接点击Run Script按钮,选择sample.py文件,你将会看到MSDN Rocks渐变文字。如果你希望自己的程序能够与视频中的效果一样:文字浮现在图片之上,那么你就得修改default.xaml文件了——把包含着Image Control的DockPanel改为Canvas即可。这个Demo还没有结束,如果就这么结束了,恐怕你会跟我没完:Demo 6.1留下的问题还没有解决呢。好,我们接下来改动一下sample.py的代码,把TextBlock中的Brushes.Black改为Brushes.Red,然后再次点接Run Script按钮,选择sample.py文件。噢,黑色的MSDN Rocks变成了红色。而在这个过程中,我们不需要进行烦琐的关闭程序、编译和重新启动的动作。这样的好处是显而易见的,我们可以仍然使用C#完成应用程序的核心部分,而将时常需要改动的部分以IronPython代码的形式存储,这样我们就能够在最短的时间内实现不同功能的切换了。Demo 6就讲述到这里了,有兴趣的朋友可以从IronPython附带的Tutorial中获得更多的信息。

Demo 7 调试IronPython程序:在这个Demo中,Jim向我们展示了如何利用VS 2005对IronPython程序进行调试。可惜的是,我并没有完成视频中的示范演示,因为VS的Debugger并不能定位到具体的.py文件,我还在找问题的原因。尽管VS Debugger并不知道IronPython的语法,但是聪明的它却可以定位到.py文件中产生错误的地方,你更可以为IronPython代码设置断点,临时修改变量值等等。IronPython就是这样与VS Debugger无缝地联系在一起,是不是很神奇呢?其实个中的原因并不难理解:IronPython代码最终是会转换为IL代码,由.NET Framework运行的,而VS Debugger自然可以认得IL了。虽然这个Demo很perfect,让人振奋,但是仍然有一个小问题:说明错误原因的Popup窗口并没有如我所愿地显示出来。了解个中原因的朋友,还请多多指教了。

Demo 8 调用COM组件:这个Demo比较可爱,通过IronPython与COM组件的协作使用MS Agent的特性。首先需要使用.NET工具中的tlbimp命令将COM组件转换成.NET程序可调用的Assembly:

D:/IronPython/Tutorial>tlbimp c:/WINDOWS/msagent/agentsvr.exe


该命令执行完毕之后就在当前目录生成了一个AgentServerObjects.dll。接着,在当前目录下创建一个merlin.py文件,具体内容如下:

import sys
sys.LoadAssemblyFromFile("AgentServerObjects.dll")
from AgentServerObjects import *
a = AgentServerClass()
id, rest = a.Load("merlin.acs")
ch = a.GetCharacter(id)

ch.SetSize(128,128)
ch.MoveTo(0, 0, 0)
ch.Show(0)
ch.MoveTo(600, 100, 2000)
ch.Play("Announce")
ch.MoveTo(300, 150, 1000)
ch.Play("Think")
ch.Play("Search")
ch.Play("Congratulate")
ch.Hide(0)


最后,通过Demo 6.2中的ImageView程序,执行merlin.py。一个很可爱的卡通人物——Merlin就会出现在你面前了,他会做不少很Q的动作,呵呵~~~ 在这里需要说明一点的是:如果你打算在Interactive Mode下面直接执行以上代码,你会碰到如下的错误:

Traceback (most recent call last):
at <shell>
System.InvalidCastException: Creating an instance of the COM component with CLSID {D45FD2FC-5C6E-11D1-9EC1-00C04FD7081F} from the IClassFactory failed due to the following error: 80004002.

这是由线程的问题引起的,解决的办法就是修改IronPythonConsole目录下PythonCommandLine.cs,在源代码的Main函数前增加[STAThread],然后重新构建这个Solution即可。

新年的开篇Post,也终于基本完成任务了,但愿遗留下来的问题不会拖得太久。最后祝各位新年快乐,身体健康,心想事成!



相关阅读:
Top