65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight 1.0 全JavaScript智能感知

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.81/5 (16投票s)

2007 年 12 月 19 日

Ms-PL

11分钟阅读

viewsIcon

32408

downloadIcon

168

一篇关于Silverlight 1.0 全JavaScript智能感知的文章

我们今天在这里所做的一切都记录在一个40分钟的网络直播中,网址是: mms://ttvv.tv/users/publicftp/justinangel/intellisense.wmv

让我们在Expression Blend 2 August preview中创建一个新的Silverlight 1.0项目,将第一页的背景颜色更改为“LightGreen”,然后绘制一个小矩形。这是我们当前的XAML文件

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    Background="#FF90EE90" <-- LightGreen
    x:Name="Page" <-- Name of Canvas
    >

    <Rectangle x:Name="myRectangle" Width="240" Height="144" Stroke="#FF000000"
        Canvas.Left="200" Canvas.Top="144"> <-- Small Rectangle
    </Rectangle>
</Canvas>

这个基本的XAML文件包含一个Canvas和一个rectangle。让我们修改rectangle,使其看起来像这样

image_thumb1

    <Rectangle x:Name="myRectangle" Width="240" Height="144" Stroke="#FF000000"
        Canvas.Left="200" Canvas.Top="144">
        <Rectangle.Fill>
            <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                <GradientStop Color="#FF1F4AB5" Offset="0.053"/>
                <GradientStop Color="#FFD97F38" Offset="0.779"/>
            </LinearGradientBrush>
        </Rectangle.Fill>
    </Rectangle>

以及一个Storyboard,使rectangle在两秒钟内改变背景颜色。

    <Canvas.Resources>
        <Storyboard x:Name="changeBackground">
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                Storyboard.TargetName="myRectangle"
                Storyboard.TargetProperty=
                "(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFD97F38"/>
                <SplineColorKeyFrame KeyTime="00:00:02.1000000" Value="#FF6BD938"/>
            </ColorAnimationUsingKeyFrames>
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                Storyboard.TargetName="myRectangle"
                Storyboard.TargetProperty=
                "(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF1F4AB5"/>
                <SplineColorKeyFrame KeyTime="00:00:02.1000000" Value="#FF5B0E54"/>
            </ColorAnimationUsingKeyFrames>
        </Storyboard>
    </Canvas.Resources>

最后,我们希望在Canvas加载时触发一个名为CanvasLoaded的JavaScript函数。

<Canvas
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480"
    Background="#FF90EE90"
    x:Name="Page"
    Loaded="CanvasLoaded"
    >
<Canvas.Resources>
    ...
</Canvas.Resources>
<Rectangle x:Name="myRectangle" Width="240" Height="144" Stroke="#FF000000"
    Canvas.Left="200" Canvas.Top="144">
     ...
 </Rectangle>
</Canvas>

让我们看看在Expression Blend 2 August Preview中这个屏幕的样子

image_thumb2

很简单。现在让我们使用Visual Studio 2008 Beta2查看位于我们Default_html.js文件中的CanvasLoaded函数。

image_thumb3

嗯,这是canvas加载事件,所以发送者必须是Canvas类型!
我们肯定能获得Canvas的智能感知。

image_thumb4

等等。什么??没有Canvas的智能感知??

嗯,我想打印出我们Canvas的背景颜色。
那么我们会写什么呢?

嗯..好吧,我猜我可以在没有智能感知的情况下工作,然后写点东西。

image_thumb5

好了,我们需要Silverlight JavaScript智能感知!

如何在Visual Studio 2008 Beta 2中使用Visual Studio Extensions for Silverlight设置Silverlight 1.0 JavaScript智能感知

  1. 请访问这里并下载最新的“JavaScript Silverlight Intellisense”版本。
  2. 打开zip文件。我们得到两个文件

    image_thumb6

  3. 将这两个文件拖放到Visual Studio 2008 Beta 2项目中。
  4. 在JS文件的顶部添加一个脚本引用。
    /// <reference path="intellisense.js" />

    image_thumb7

  5. 在我们的HTML页面中,为intellisense.js添加一个script src。
    <script type="text/javascript" src="intellisense.js"></script>

image_thumb8

就是这样!
我们完成了。
现在您已经拥有Silverlight 1.0的JavaScript智能感知。

我们要做的第一件事是将我们的sender转换为一个强类型Canvas对象。

image_thumb9

现在让我们看看从这个奇怪的Convert.ToCanvas函数中得到了什么。

image_thumb10

image_thumb11 image_thumb12image_thumb13image_thumb14

我们在JavaScript代码中获得了Silverlight对象的完整智能感知!

我们获得了属性、事件、方法、集合、索引器,它们都是强类型的!

处理属性

所以让我们打印出我们Canvas的背景。

image_thumb15

我们甚至在JavaScript中获得了SDK注释!

image_thumb16

但是这是什么?...这个背景属性给了我们一个Brush?什么是brush

image_thumb17

等等,我们用的是SolidColorBrush,那么它和这个Brush有什么关系?

image_thumb20

好的,那么让我们把我们的BrushConvertSolidColorBrush

image_thumb22

我们得到了新的Color属性!
让我们打印出来。

image_thumb24

在我们的屏幕上,我们得到

image_thumb23

我们得到-7278960,这是一个RGB值,代表LightGreen。

所以,让我们做一些更棘手的事情,让我们改变我们Canvas的背景。
我们将创建一个新的SolidColorBrush

image_thumb25

image_thumb27

image_thumb26

image_thumb28

image_thumb29

我们的背景颜色已经改变了!

image_thumb30

处理方法

还记得我们添加了一个动画,让我们的Storyboard改变背景颜色吗?
让我们启动那个Storyboard

<Canvas.Resources>
<Storyboard x:Name="changeBackground">
...
</Storyboard>
</Canvas.Resources>

让我们在我们的canvas上使用findName方法。

image_thumb31

image_thumb32

您注意到我们的FindName方法返回一个DependencyObject类型的类了吗?

image_thumb33

我们需要将通用的DependencyObject转换回Storyboard

image_thumb34

以前

image_thumb36

操作后

image_thumb35

处理事件和全局类型变量

让我们捕获鼠标左键单击事件,让我们的canvas将不透明度更改为0.3。

image_thumb37

image_thumb38

function CanvasLoaded(sender, eventArgs)
{
    var someElement = Convert.ToCanvas(sender);
    ...
    someElement.add_MouseLeftButtonDown(OnMouseLeftButtonDown);
}

function OnMouseLeftButtonDown(sender, eventArgs)
{

}

我们可以看到Canvas元素在新的OnMouseLeftButtonDown方法中超出了作用域,所以我们必须将someElement移到更高的作用域。

var someElement;
function CanvasLoaded(sender, eventArgs)
{
    someElement = Convert.ToCanvas(sender);
    ...
}

function OnMouseLeftButtonDown(sender, eventArgs)
{

}

让我们看看我们在智能感知方面是如何处理的。

image_thumb39 image_thumb40

在我们将sender转换为Canvas之后,我们在CanvasLoaded中获得了someElement的智能感知,但在OnMouseLeftButtonDown中却没有。
我们需要将someElement定义为一个类型为Canvas的全局变量。

image_thumb41

现在让我们把不透明度改为0.3,就像我们想要的。

image_thumb42

最终结果...

在点击鼠标左键之前

image_thumb43

操作后

image_thumb44

处理内联函数(匿名委托)和附加属性

当我们在键盘上按下箭头键时,让我们的rectangleCanvas周围移动。

image_thumb45

image_thumb46

这与C# 2.0匿名委托使用的语法非常相似。

为了获取按下的键,我们需要eventArgs.Key属性,所以让我们转换我们的eventArgs

image_thumb47

我碰巧知道(因为Jon Galloway告诉我们)“15”代表向上箭头键。

image_thumb48

好的,现在我们需要将我们的Rectangle向上移动...所以让我们改变它的Canvas.Top附加属性。image_thumb49

请注意,我们正在使用DependencyObjectsetValuegetValue,它们并非仅限于Rectangle

image_thumb50

让我们创建我们的Canvas.Top依赖属性。

image_thumb51

someElement.add_KeyUp(function(sender, eventArgs)
{
    var e = Convert.ToKeyboardEventArgs(eventArgs);
    if (e.get_key() == 15)
    {
        var rect = someElement.findName("myRectangle");
        var top = Convert.ToDependencyProperty("Canvas.Top");
        rect.setValue(top, rect.getValue(top) - 10);
    }
});

在点击向上箭头按钮之前

image_thumb52

操作后

image_thumb53

多态性和Is/As模式

如果您曾经使用过C#,您将非常熟悉类型转换的Is/As模式。

Is类型转换模式

image_thumb54

As类型转换模式

image_thumb55

我们在这里看到的是基本的多态性。我们获得了一个Perctangle类型,将其引用类型改回其父类DependencyObject,然后再改回Rectangle

image_thumb56

我们在JavaScript代码中也有类似C# Is/As模式的模式。

JavaScript Is模式

image_thumb57

JavaScript As模式

image_thumb75

“Convert.IsXXX”方法返回一个值,无论元素是否可以转换为XXX。
“Convert.ToXXX”方法在值不可转换为XXX时返回null

处理扩展方法

假设我们经常改变前面看到的RectangleCanvas.top附加属性。
如此普遍,它应该是一个扩展方法。

我们希望将其添加到Rectangle类的智能感知中,而无需更改原始类代码。

C# 3.0语法如下

image_thumb59

image_thumb60

我们向Rectangle类添加了一个新方法,而无需更改其代码!

我们在JavaScript Silverlight对象中做同样的事情。

我们将创建一个名为Extensions.js的新文件(因为它是一个好名字)

image_thumb61

我们需要向我们的intellisense.js文件添加一个引用。
我将通过在解决方案资源管理器中选择intellisense.js文件并将其拖放到我们的Extensions.js文件中来实现。

image_thumb62

让我们将我们的Extension方法添加到Rectangle

image_thumb63

image_thumb64

image_thumb65

我们需要确保ChangeByHowMuch是一个已知的Number类型,所以我们将添加一个param语句。

image_thumb66

现在让我们改变我们RectangleCanvas.Top

image_thumb67

image_thumb68

现在让我们将这个Extensions.js文件作为script标签引用到我们的HTML页面。

image_thumb70

image_thumb69

并且我们需要在需要智能感知的地方引用我们的Extensions.js文件。

image_thumb71

请注意,我们不再直接引用intellisense.js文件。我们的extensions.js引用它,所以我们不需要。

image_thumb72

image_thumb74

运行此代码后,我们可以看到矩形位于我们Canvas的底部

image_thumb77

类型安全、隐藏元素字段和JavaScript调试

让我们看一下这个方法

image_thumb78

它期望一个Double类型的Number。所以这个参数是可以接受的

canvas.set_opacity(0.5);

但是关于...

canvas.set_opacity("really shiny opacity please!");

让我们先将此代码直接运行到Canvas Silverlight CLR类型。

我们可以通过使用我们Silverlight JavaScript类上的Element隐藏字段来访问它。

image_thumb80

请注意,我们没有获得我们元素类型的任何智能感知。

var canvas = Convert.ToCanvas(sender);

canvas.element.opacity = "really shiny opacity please!";

我们直接从Silverlight 1.0 CLR那里得到了这个有些神秘的错误消息

image_thumb81

让我们用我们的Silverlight JavaScript智能感知对象试试。

var canvas = Convert.ToCanvas(sender);

// canvas.element.opacity = "really shiny opacity please!";
canvas.set_opacity("really shiny opacity please!");

然后我们得到

image_thumb79

让我们打开JavaScript调试的调用堆栈窗口。

image_thumb82

在调用堆栈中,我们可以看到

image_thumb83

我们可以看到是TypeSafety检查失败了。
双击第二行

image_thumb84

我们在编辑器中可以看到

image_thumb85

现在,只是为了好玩,让我们打开我们的快速监视窗口(自VS2003以来是CRTL + ALT + Q)并评估this

image_thumb86

image_thumb87

image_thumb88

我们可以看到我们Silverlight JavaScript智能感知对象上的所有属性、方法和事件。

让我们检查this.element,这是普通的Silverlight CLR 1.0对象。

image_thumb89

什么也没有,我们没有原生Silverlight对象的JavaScript调试监视。

现在,让我们尝试将一个字符串添加到我们的Canvas.Children集合中。

image_thumb90

image_thumb91

var canvas = Convert.ToCanvas(sender);
canvas.get_children().add("blue shiny rectangle");

我们得到了以下运行时错误

image_thumb92

让我们尝试一些更微妙的东西。还记得这段代码吗?

image_thumb93

我们使用了多态性,将一个继承自BrushSolidColorBrush作为Brush参数发送。
让我们将SolidColorBrush转换回DependencyObject并将其发送到方法

image_thumb94

这工作正常,没有引发错误。

让我们尝试发送一个被引用为DependencyObjectRectangle

image_thumb95

我们得到以下错误

image_thumb96

我们需要一个Brush
我们可以得到一个SolidColorBrush,因为它继承自Brush
我们可以得到一个SolidColorBrushDependencyObject,因为SolidColorBrush仍然继承自Brush
我们不能将RectangleDependencyObjectConvertBrush

部署

使用自定义智能感知JavaScript语法进行开发会导致部署问题。

我们是将intellisense.js部署到客户端浏览器吗?还是从JavaScript代码中剥离智能感知功能?
我们可以根据需要做任何事情。

带有Intellisense.js文件的部署

看看intellisense.js的文件大小。

image_thumb98

它超过1MB!太大了!

而且大部分实际上是注释、空格和变量名。
所以,通过下载intellisense.js文件,您将获得一个名为intellisense.compressed.js的被剥离了内容的版本。

您可以将脚本标签HTML引用更改为这个压缩后的JavaScript文件,您的客户只会下载压缩版本,而您仍然可以获得完整的智能感知。

image_thumb100

image_thumb102

在生成Intellisense.js文件的过程中,我们使用了Atif Aziz的JavaScript压缩器来创建这个压缩版本。
您可以看到它只压缩到完整intellisense.js文件的40%左右。

市面上有成百上千的JavaScript压缩器,有些将我们的intellisense.js文件压缩成了**仅仅100KB的文件**。
如果您想找到它们,只需在Google上搜索:“JavaScript compressor”或“JavaScript shrink”。

但是,通过下载,我只能提供一个基于.NET的软件的压缩文件。
但是您可以随意使用您自己的压缩器处理这个文件,并根据需要进行部署。

如果您找到一个具有更好结果并且是用.NET编写的压缩器,我很乐意使用它。

不带Intellisense.js文件的部署

项目Codeplex页面上有两个下载在此
第一个只包含前面提到的两个JavaScript文件。

image_thumb114

第二个下载包含生成intellisense.js的.NET软件的代码。
不用担心,您不需要它。

在该软件内部,有以下屏幕

image_thumb103

(您现在可能在想:“所以,这是那个告诉我如何使用Silverlight的人?那一定是史上最丑的屏幕!”)

让我们使用今天编写的以下JavaScript代码

var someElement = Convert.ToCanvas(null);
function CanvasLoaded(sender, eventArgs)
{
    someElement = Convert.ToCanvas(sender);
    var brush = Convert.ToSolidColorBrush(someElement.get_background());
    alert(brush.get_color();
    var newBrush = SolidColorBrush.createFromXaml(sender.getHost());
    newBrush.set_color(Convert.ToColor("Aqua"));
    var newBrushAsDependencYObject = Convert.ToDependencyObject(newBrush);
    someElement.set_background(newBrushAsDependencYObject);
    Convert.ToStoryboard(someElement.findName("changeBackground")).begin();
    someElement.add_MouseLeftButtonDown(OnMouseLeftButtonDown);
    someElement.add_KeyUp(function(sender, eventArgs)
    {
        var e = Convert.ToKeyboardEventArgs(eventArgs);
        if (e.get_key() == 15)
        {
            var rect = someElement.findName("myRectangle");
            var top = Convert.ToDependencyProperty("Canvas.Top");
            rect.setValue(top, rect.getValue(top) - 10);
        }
    });
}

并将其复制到“JavaScript with intellisense”文本框中。

image_thumb105

我们得到相同的JavaScript代码,但没有任何智能感知功能。

它使用普通的Silverlight CLR对象。

这是完整的翻译代码

var someElement = null;
function CanvasLoaded(sender, eventArgs)
{
    someElement = sender;
     var brush = someElement.background;
    alert(brush.color);
    var newBrush = sender.getHost().content.createFromXaml("<SolidColorBrush />");
    newBrush.color = "Aqua";
    someElement.background = newBrush;
    someElement.findName("changeBackground").begin();
    someElement.addEventListener("MouseLeftButtonDown", OnMouseLeftButtonDown);
    someElement.addEventListener("KeyUp", function(sender, eventArgs)
    {
        var e = eventArgs;
        if (e.key == 15)
        {
            var rect = someElement.findName("myRectangle");
            var top = "Canvas.Top";
            rect.setValue(top, rect.getValue(top) - 10);
        }
    });
}
}

所以我们甚至不需要在部署场景中包含任何JavaScript文件。

image_thumb109

这个小工具只是一个从JavaScript中移除智能感知代码的简单示例。
我们可以对Visual Studio 2008插件使用相同的机制,该插件可以在智能感知代码和非智能感知代码之间进行转换。
我们可以创建一个小型的.NET IHttpHandler,它将只向浏览器请求提供已移除智能感知代码的JavaScript文件。

所以关于部署,取决于您。
如果您需要我的任何帮助,我都在。

问题、后续和建议

Bug

您会在此智能感知中发现bug。
说真的,我没聪明到能在10小时内构建一个完美的类型系统。

请访问项目Codeplex页面在此创建一个新问题。
写下您收到的错误,添加相关的最小化代码。
如果某项功能不按预期工作,请告诉我您的预期以及实际发生的情况。

如果可能,附加截图。

image_thumb113

功能请求

此外,您可能还需要其他功能,例如我提到的HttpHandler,或者更多需要强类型化的内容(例如DependencyPropertiesKeys)。
同样,打开一个新问题,我会尽力而为。

检查更新

此项目在发布后的前30-60天内必将经历持续的变更。
如果您正在使用此项目,请订阅我们的RSS feed,以便及时收到通知。
RSS feed可以在此处找到。

万一Codeplex页面不够,这里是我的个人联系方式
Justin-Josef Angel,
高级.NET顾问,Microsoft C# MVP
电子邮件: J@JustinAngel.Net
电话: +972 546 567789

我对此是认真的,请不要犹豫与我联系。

好了,就这样。

历史

  • 2007年12月20日:发布于The Code Project
  • 2007年8月1日:发布于CodePlex
© . All rights reserved.