动态语言和 Silverlight
2009-02-07 11:57:44 来源:WEB开发网目录
获得 DLRConsole
使用 DLRConsole
深入了解代码
2 + 2 这个问题有多难?
别急,还有更多需要讨论
立即动手尝试吧!
孩子们是从创造性的玩耍中学习知识的。从乐高 (LEGO) 玩具到 GI Joe 玩具和芭比娃娃(我发誓,这些都是我姐姐的玩具),孩子们总是一把拿起玩具,然后凭直觉来鼓捣它们,他们不会拿出玩具手册来阅读,至少不会为了解玩具的玩法而阅读手册!当“做事情的正确方式”尚未深深地印入脑海时,通过体验和摆弄东西来了解事物可以说是人类的本性,儿童尤其如此。勿庸置疑,这种动手实践是一种最佳的学习方法。
以同样观点来看软件,动态语言通常与交互环境相关联,为您提供一种“执行 - 评估 - 输出”的循环(Run-Evaluate-Print Loop,REPL),允许使用探索性的“尝试 - 错误”法进行编程。从某种意义说,REPL 方法使编程变成一种注重动手操作的“玩耍”。这就是为什么动态语言的倡导者常常说,“你只要摆弄一下就知道是怎么回事了”。
当我的团队将动态语言集成到 Silverlight™ 中时,大家马上就想让它能够结合 Silverlight 一起使用。Jim Hugunin 只做了一些巧妙的编程,DLRConsole 就诞生了。本专栏将探讨 DLRConsole 的工作原理,并进而讨论 IronPython、DLR 托管以及 DLR 与 Silverlight 的集成。
获得 DLRConsole
本地运行 DLRConsole
您可以将 DLRConsole 下载到本地计算机上运行,但是设置上稍微复杂一些,因为这需要 Web 服务器的支持。在设置好 Web 服务器后,您即可解压缩 DLRConsole.zip 文件,并将该文件夹置于 Web 服务器的文件夹中,然后在您的 Web 服务器上导航到 /DLRConsole/index.htm。(如何在计算机上设置 Web 服务器不在本专栏的讨论范围内,但您可以在 iis.net/articles/view.aspx/IIS7/Deploy-an-IIS7-Server/Installing-IIS7/Install-IIS7-on-Vista 上找到 Windows Vista 下的一些设置指南,以及在 docs.info.apple.com/article.html?path=Mac/10.4/en/mh1921.html 上找到 Mac OS 10.4 下的一些设置指南。)
在自己的 Web 服务器上运行时只需注意一点,即需要将服务器的配置设置为支持 DLR 语言。如果出现以下错误消息,则说明有问题:
Silverlight error message
ErrorCode: 2024
ErrorType: ParserError
Message: Invalid attribute value text/python.
XamlFile: DLRConsole.xaml
Line: 6
Position: 53
这时您需要将以下 MIME 类型映射添加到服务器配置中:
.py == text/python
.jsx == text/jscript
至此,就可以庆贺一下了:您可以运行 DLR Silverlight 应用程序了!
但是,在深入探讨 DLRConsole 之前,我或许应该先大致介绍一下动态语言运行时 (DLR),这是一个运行于 CLR 之上的动态语言支持系统,它提供了大多数动态语言实现所需的语言服务。这些服务包括动态类型系统、动态方法调度、动态代码生成和宿主 API。有关 DLR 的详细信息,请参阅 Jim Hugunin 的博客文章,网址为 blogs.msdn.com/hugunin/ archive/2007/04/30/a-dynamic-language-runtime-dlr.aspx。
DLRConsole 是一个 Silverlight 1.1 示例,演示了一个非常轻量级的代码开发和实验工具。(请注意自 2008 年 1 月 1 日起,Silverlight 1.1 已更名为 Silverlight 2.0。)它允许您编辑和执行 XAML 和 Python 代码,并在支持代码着色和代码自动完成的交互式编辑器中使用 Python 和 JScript® 进行实验。
DLRConsole 从两方面体现了 DLR 与 Silverlight 的集成。一方面,它是一个用 DLR 兼容的语言 IronPython 编写的 Silverlight 应用程序。另一方面,它利用了 DLR 宿主 API 来执行键入到控制台和编辑器中的 DLR 代码。
您可以从 silverlight.net/Samples/1.1/DLR-Console/DLRConsole.zip 下载 DLRConsole 代码到本地执行。如果您只想交互式地使用 DLRConsole,请访问 silverlight.net/Samples/1.1/DLR-Console/python 上的托管版本。要运行 DLRConsole,您的计算机上必须安装 Silverlight。在未安装 Silverlight 的情况下运行 DLRConsole 时,程序会提示您 Silverlight 的下载链接;但如果您希望提前安装适用于 Windows® 或 Apple 平台的 Silverlight,请访问 microsoft.com/silverlight/install.aspx。如果您使用的是基于 Linux 的操作系统,请访问 mono-project.com/Moonlight,参考针对 Linux 的 Silverlight 实现 - Mono 的 Moonlight 项目。
使用 DLRConsole
在浏览器中运行 DLRConsole 的方法有两种,一种是从 silverlight.net 运行,另一种是在自己的计算机上本地运行。出于本专栏的目的,我将演示从 Silverlight.net 运行的方法,但如果您希望下载 DLRConsole.zip、浏览该代码以及在自己的开发机或本地服务器上运行,请参阅“本地运行 DLRConsole”侧栏提供的一些实用技巧。
首先,请在浏览器中打开 silverlight.net/Samples/1.1/DLR-Console/python。就是这样!您应该能在浏览器中看到 DLRConsole 打开时的情景,如图 1 所示。
图 1正在打开 DLRConsole
加载 DLRConsole 时,会显示 Python 命令提示符,供您逐行键入 Python 代码,键入代码后您可以立即在控制台或 Silverlight 画布中看到其效果,如图 2 所示。您可以单击不同的语言将控制台切换到相应的语言,并查看所选语言的示例代码块。在键入语句时尝试混合搭配使用各种语言,并注意比较不同语言完成工作的方式。
图 2正向控制台中写入代码
XAML 选项卡显示的是 Silverlight Canvas 初始窗格的 XAML 代码(参见图 3)。您可以编辑该代码或添加其他代码,然后按 Ctrl+Enter 更新画布。
图 3XAML 窗格
Python Code 选项卡显示 Python 代码块,该代码块将生成带有文字的蓝色背景,鼠标悬停在文字上方时文字会改变颜色。同样,在第一次更改和进行任何更改之后,您需要按 Ctrl+Enter 才能执行此代码。
About 选项卡提供了到 CodePlex 上 Dynamic Silverlight 网页的链接 (codeplex.com/dynamicsilverlight)。
深入了解代码
您已经了解了 DLRConsole 可以做些什么,下面来看看 DLRConsole 由哪些文件组成,以及 DLRConsole 的工作原理。图 4 列出了下载的 DLRConsole 包中包含的源文件。
Figure4DLRConsole 源文件
文件 | 说明 |
Index.htm | 简单的 HTML 页面,包含 Silverlight.js 和 CreateSilverlight.js,并对 CreateSilverlight 进行调用。 |
Silverlight.js | 包含在浏览器中创建 Silverlight 应用程序的逻辑。 |
CreateSilverlight.js | 定义 CreateSilverlight,用以初始化 Silverlight 和加载 DLRConsole.xaml。 |
DLRConsole.xaml | 一个指向 DLRConsole.py 的 XAML 小文件,该文件将 Loaded 事件绑定到 OnLoaded python 方法。 |
DLRConsole.py | 包含应用程序的所有功能。 |
Wpf.py | 定义帮助程序方法,以便与 WPF API 进行交互。 |
README.txt | DLRConsole 文档。 |
文件 Index.htm、Silverlight.js 和 CreateSilverlight.js 用于初始化 Silverlight。尽管这些文件很重要,但本文并未打算对其进行讨论。您可以在 silverlight.net/QuickStarts/Start/CreateProject.aspx 上找到关于 Silverlight 项目基本设置的详细介绍。
Wpf.py 是一个 Python 文件,它为与 WPF 进行交互定义了一些帮助程序,如 LoadXaml(url):
def LoadXaml(url):
uri = MakeUri(url)
request = System.Windows.Browser.Net.BrowserHttpWebRequest(uri)
response = request.GetResponse()
reader = System.IO.StreamReader(response.GetResponseStream())
xaml = reader.ReadToEnd ()
reader.Close()
return XamlReader.Load(xaml)
这种方法实际上是下载所提供的 URL 并返回 XamlReader.Load 的结果。
DLRConsole.xaml 会加载 DLRConsole.py,然后调用 Python 代码中定义的 OnLoaded 方法。它起到的是占位符的作用,因为 Silverlight 1.1 Alpha 应用程序要求必须有一个 XAML 文件。(预计 Silverlight 的未来版本会有所更改,无需引导像 DLRConsole.xaml 这样的 XAML 文件即可进行加载。)需要强调的是 x:Code 标记,这是一个连接到 DLR 的挂钩,使 Silverlight 能够加载文件并使用 DLR 执行文件。这样,以 XAML 定义的任何事件都可以绑定到以 DLR 语言定义的方法。Canvas 从定义上讲就是让 Python 代码运行。
<Canvas x:Name="root" Width="1000" Height="500"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<x:Code Source="DLRConsole.py" Type="text/python" />
<Canvas x:Name="loadingHelper" Loaded="OnLoaded" />
</Canvas
由于总共有 2164 行的 Python 代码,因此我并不打算完完整整地展示 DLRConsole.py 的全部内容,而是只讨论最有趣的部分。
从 XAML 文件被加载、OnLoaded 被调用那一刻起,Silverlight 即开始由 Python 和 DLR 驱动。OnLoaded 初始化 Application 类,最终您会执行到 Application.Initialize(self) 方法。屏幕上所有内容都出自于此。它会注册 KeyHandler,创建 ConsoleWindow、Editors 和其余用户界面,并启动控制台以便您进行交互式体验。
2 + 2 这个问题有多难?
现在,您有了一个在浏览器中运行的交互式控制台。哇,看上去不错!下面就让我们来一次典型的动态语言测试:2 + 2,看看会有什么事情发生。
首先,在控制台中键入“2 + 2”。
py> 2 + 2
4
py>
在键入的同时您可能希望看到自己键入的内容。但是,从 WPF 角度来看,这需要通过 Application 的 Initialize 方法的第一行来实现:
self.KeyHandler = TextInputHandler(self.root)
此代码构造了 TextInputHandler,它定义了按键的文本表示,并将 TextInputHandler 的 OnKeyDown 方法绑定到根 Canvas 的 KeyDown 事件。在每次 KeyPress 时,它会为按下的键构造一个带文本表示的 KeyPress 对象,并告知其 Target 处理按键操作。Target 可以是具有 HandleKey 方法的任何类。在本例中为 ConsoleInput,它通过 TextBuffer 对象在光标处插入文本表示来处理键输入,并将光标移到下一列。
尽管这需要花费一些时间,但除了使用 WPF 外并没有什么新办法。但是,在按 Enter 时,您会希望该语言计算该行的结果并显示答案。在本例中,是用所选语言在用户浏览器中进行计算!这就是非常有趣的地方,下面我们来详细介绍一下它的工作原理。
首先,本例中处理按键操作的方法如下:
def HandleKey(self, key):
if key.Text == 'n':
self.DoInput(key.Ctrl)
elif key.Text == '.':
self.DoCompletions()
elif key.Name == 'Up' and self.Caret.line == 0:
self.DoHistory()
else:
Editor.HandleKey(self, key)
在本例中,DoInput 调用了 DoSingleLine,后者会尝试解析表达式。如果解析成功,它会计算表达式的结果,并将输出内容写入到控制台,同时设置“_”自由变量 (Convenience Variable)(参见图 5)。如果有兴趣,您可以查看源代码了解 TryExpression 是如何解析表达式,以及 GetEngine 是如何创建 LanguageEngine 的。
Figure5DOSingleLine 分析
def DoSingleLine(self, text, forceExecute):
text1 = self.le.TryExpression(text)
if text1:
self.WriteInputToConsole(text)
try:
ret = self.Engine.Evaluate(text1, self.CurrentModule)
if ret is not None:
self.console.write(repr(ret) + 'n', 'output')
self.CurrentModule.SetVariable('_', ret)
except Exception, e:
self.HandleException(e)
else:
self.DoMultiLine(text, forceExecute)
这就是在 DLRConsole 中计算 2+2 所需要的操作。实际上,该示例涵盖了所有可以处理的单行指令。通过少量变体,您也可以处理多行指令。而最有趣的地方是 DLRConsole 是调用 DLR 来执行代码的。
别急,还有更多需要讨论
2 + 2 是一个非常简单的例子。面对更复杂的情况会怎样呢?好了,我们以 .NET Framework 集成为例看一下情况如何。请看以下示例:
py> import System
py> from System.Collections import *
py> h = Hashtable()
py> h["a"] = "IronPython"
py> h{"b"] = "in Silverlight"
py> for e in h: print e.Key, ":", e.Value
a: IronPython
b: in Silverlight
如您所见,您可以从 IronPython 使用 System.Collections,它的工作方式类似 Python 散列或 .NET Framework 散列,无论您选择何种方式。我在《MSDN® 杂志》2006 年 10 月刊 (msdn.microsoft.com/msdnmag/issues/06/10/CLRInsideOut) 中使用了同一示例,只是现在是在浏览器中运行。有空的时候您可以阅读这篇文章,详细了解 IronPython 和 .NET 的集成,但是请记住,文章的内容可能已经有些过时。有关其他信息,可以访问 blogs.msdn.com/ironpython。
那么与画布的交互又怎样呢?让我们看看 Application 类的 StartConsole 方法:
def StartConsole(self, console, canvas, langInfo):
...
console.CurrentModule.SetVariable("canvas", canvas)
console.CurrentModule.SetVariable("wpf", wpf)
...
当 DLRConsole 初始化控制台时,它会自动为您设置几个变量,其中包括一个 WPF 帮助程序模块和一个指向画布的指针。有了这些变量,您就可以编写如图 6 所示的代码,它将实现鼠标划过时颜色变化的效果。如果要在运行中查看此代码,请选择 Python Code 选项卡,并按 Ctrl+Enter。
Figure6鼠标划过事件
import wpf
canvas.Background = wpf.BlueBrush
r = wpf.TextBlock()
r.Text = "Touch Me"
canvas.Children.Add(r)
r.FontSize = 60
wpf.SetPosition(r, 40, 60)
def light(s, e):
s.Foreground = wpf.SolidColorBrush(wpf.Colors.White)
def dark(s, e):
s.Foreground = wpf.SolidColorBrush(wpf.Colors.Black)
r.MouseEnter += light
r.MouseLeave += dark
在键入这些示例时,您是否注意到在键入后带句点的类名或对象名时会弹出一个小框?DLRConsole 支持一种团队成员喜欢称之为“代码联想”(Code-Sense) 的功能。这种功能并不像 Visual Studio® IntelliSense® 的功能那么高级,它只是一个示例,但在查找适用于给定对象的方法或属性时却很有帮助(参见图 7)。
图 7代码自动联想
借助此功能,您可以使用向上/向下键选择需要的元素,按 Enter 进行选择,然后继续键入其他内容。要了解此功能的用法,让我们再看看 HandleKey 方法:
def HandleKey(self, key):
if key.Text == 'n':
self.DoInput(key.Ctrl)
elif key.Text == '.':
self.DoCompletions()
elif key.Name == 'Up' and self.Caret.line == 0:
self.DoHistory()
else:
Editor.HandleKey(self, key)
对于只有 100 多行的 Python 代码而言,这是一个非常不错的功能。
从 Python 到 JScript
前面我提到过,DLRConsole 支持多种 DLR 语言,目前发布的版本支持 Python 和 JScript。由于这些语言都构建于 DLR 之上,因此它们不仅能与 .NET 集成,而且还可以跨语言共享声明。以下演示了如何在 Python 与 JScript 之间共享变量和方法:
js> a = 2 + 2
4.0
py> b = a * 2
py> b
8.0
js> function times10(n) {
js| return n * 10
js| }
py> times10(5)
50.0
要完成此操作,您只需单击要使用的编程语言,控制台提示、语法着色,当然还有语言,即会做相应更改。这通过告知控制台设置其语言并委托给 Editor 来实现:
def SetLanguage(self, name):
self.le = GetEngine(name)
self.Engine = self.CurrentEngine = self.le.engine
self.TokenCategorizer =
self.Engine.LanguageProvider.GetTokenCategorizer()
乍看起来这好像并不实用,但实际上它让开发人员可以随意选用自己熟悉的语言,而不必因实现语言而限制自己的代码使用,从而能够获得前所未有的代码重用性。事实表明,开发人员在使用自己熟悉的语言编写程序时最富有创造性,因此,这甚至可以极大地改善软件的质量。
立即动手尝试吧!
DLRConsole 让您能够以最低的投入来探索和研究 Silverlight 及动态语言的使用,除了 Silverlight 以外,您甚至不需要安装任何软件。与在其他人托管的沙盘中进行实验相比,还有更好的选择吗?
请时常访问 codeplex.com/dynamicsilverlight,关注有关 Silverlight 中动态语言集成新版本的信息,以及 Silverlight 动态语言示例的新版本和更新版本。下一版本应该也会包含对 IronRuby 的支持,您现在就可以从 www.ironruby.net 上下载 IronRuby。当然,您也可以像以往一样,从 codeplex.com/ironpython 下载 IronPython。如果您有兴趣了解更多 Silverlight 示例,可以从 Silverlight 社区库中找到大量有趣的示例,网址是:silverlight.net/community/communitygallery.aspx。
Tags:动态 Silverlight
编辑录入:爽爽 [复制链接] [打 印]- ››Silverlight for Windows Phone 7开发系列(1):...
- ››Silverlight for Windows Phone 7开发系列(2):...
- ››Silverlight for Windows Phone 7开发系列(3):...
- ››Silverlight for Windows Phone 7开发系列(4):...
- ››动态调用对象事件
- ››动态创建控件支持事件响应并可保存与读取
- ››Silverlight for Symbian
- ››动态截获并显示窗口DC
- ››动态改变 Android 控件大小
- ››动态分区迁移主要准备过程及典型问题分析
- ››动态更改 Android 的屏幕方向
- ››Silverlight3系列(四)数据绑定 Data Binding 1
赞助商链接