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

Silverlight 集成到 ASP.NET AJAX 控件 (十五数码游戏)

2008年5月26日

CPOL

4分钟阅读

viewsIcon

83175

downloadIcon

1206

将 Silverlight 集成到 ASP.NET AJAX 控件中 (十五数码游戏)。

Screenshot2.jpg

引言

最近,我对一项名为 Silverlight 的非常棒的技术产生了兴趣,并且我正在尝试学习它,因为它非常强大。

事实上,Silverlight 有两个版本

  • Silverlight 1.0 发布
  • Silverlight 2.0 Beta 1

1.0 和 2.0b1 之间的区别很大

  • 支持客户端的 .NET 语言 (C#, VB.NET,..) 而非 JavaScript
  • 来自 WPF 的大量控件
  • Framework 3.5 的子集 (LINQ, ...)

有关差异的完整列表,请参见 此处

不幸的是,要轻松使用 Silverlight 2.0 Beta 1,需要 Framework 3.5 和 Visual Studio 2008 Personal 或更高版本。

我的想法是将 Silverlight 控件集成到 ASP.NET AJAX 控件中,但如果没有 Visual Studio 2008,这似乎相当困难。因此,我使用 Visual Studio 2005 将 Silverlight 1.0 控件集成到了 ASP.NET AJAX 控件中。

背景

通常,当我开始学习一项新技术时,我总是尝试实现一个非常简单的示例,但为了使其更有趣,我会实现一个完整的应用程序或游戏。

在我小时候,家里没有电脑,我花了一些空闲时间玩一款名为“十五数码游戏”的游戏。这是一款非常简单的游戏,但一开始并不绝对容易解决。有关该游戏的更多详细信息,请参见此 链接。我在 Silverlight 1.0 中实现了它,并将其集成到了 ASP.NET AJAX 控件中。

Using the Code

解决方案分为以下项目

  • Web 应用程序:包含托管该控件的 ASP.NET 页面
  • 类库:包含该控件

在 Web 应用程序中,我们有一个 ASP.NET Web 窗体,其中包含该控件和 ScriptManager (ASP.NET AJAX 框架的核心)。

在控件中,我们有以下文件

  • FifteenPuzzle.cs:服务器端控件,继承自 ScriptControl
  • FifteenPuzzle.js:包含 JavaScript 类的 JavaScript,该类将 Silverlight 控件集成到 ASP.NET AJAX 控件中;
  • FifteenPuzzle.xaml:描述控件静态部分的 XAML (动态部分在 JavaScript 类中生成);
  • Helper.js:包含相同有用函数的 JavaScript;
  • Silverlight.js:用于将 Silverlight 控件实例化到 HTML div 中的标准 JavaScript;

FifteenPuzzle 继承自 ScriptControl (服务器端所有 ASP.NET AJAX 控件的基类) 并重写了两个方法

  • GetScriptDescriptors:用于使用 JSON 格式将参数传递给 JavaScript 类的 \u53d8\u91cf\u3002
    • xamlUrl:用于生成 Silverlight 中 XAML 静态部分的资源 URL。
    • width, height:控件的尺寸。
    • imageUrl:在游戏处于 puzzleRenderMode.Image 模式时使用。
    • puzzleRenderMode:用于定义渲染游戏的两种不同模式 (NumberImage) 的枚举。
  • GetScriptReferences:用于传递脚本 URL 的方法 (我使用了 GetWebResourceUrl,因为我将所有脚本嵌入到了程序集中)
    • Controls.Resources.FifteenPuzzle.js:包含 AJAX 控件的 JavaScript 类,继承自 Sys.UI.Control
    • Controls.Resources.Helper.js:包含一些实用函数。
    • Controls.Resources.Silverlight.js:用于将插件实例化到 div 中的默认 Silverlight JavaScript。
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = 
         new ScriptControlDescriptor("Controls.FifteenPuzzle", this.ClientID);
    descriptor.AddProperty("xamlUrl", this.Page.ClientScript.GetWebResourceUrl(
         this.GetType(), "Controls.Resources.FifteenPuzzle.xaml"));
    descriptor.AddProperty("width", this.Width.ToString());
    descriptor.AddProperty("height", this.Height.ToString());
    descriptor.AddProperty("imageUrl", this.ImageUrl);
    descriptor.AddProperty("puzzleRenderMode", this.PuzzleRenderMode);

    yield return descriptor;
}

protected override IEnumerable<ScriptReference> GetScriptReferences()
{
    List<ScriptReference> scripts = new List<ScriptReference>();

    ScriptReference scriptReference1 = new ScriptReference();
    scriptReference1.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                            "Controls.Resources.FifteenPuzzle.js");
    scripts.Add(scriptReference1);

    ScriptReference scriptReference2 = new ScriptReference();
    scriptReference2.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                            "Controls.Resources.Helper.js");
    scripts.Add(scriptReference2);

    ScriptReference scriptReference3 = new ScriptReference();
    scriptReference3.Path = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                            "Controls.Resources.Silverlight.js");
    scripts.Add(scriptReference3);

    return scripts;
}

文件 Controls.Resources.FifteenPuzzle.js 包含 JavaScript 类 Controls.FifteenPuzzle,该类封装了大部分逻辑。

每个拼图块的位置包含在一个 4x4 的数组中。开始时,数组被初始化为正常顺序,并使用 JavaScript 动态渲染拼图块。

puzzleRenderMode 设置为 Number 时,为每个拼图块生成的 XAML 如下

<Canvas Name="FifteenPuzzle1_Cell_15" Canvas.Left="219" 
         Canvas.Top="370" Canvas.ZIndex="3" Width="100" 
         Height="100" Background="White" Cursor="Hand">
  <Rectangle Fill="#80000000" Width="98" Height="98" 
     Canvas.Top="2" Canvas.Left="2" 
     RadiusX="15" RadiusY="15">
  </Rectangle>
  <Rectangle Width="100" Height="100" 
       Canvas.Top="0" Canvas.Left="0" 
       RadiusX="15" RadiusY="15">
    <Rectangle.Fill><LinearGradientBrush 
             StartPoint="0,0" EndPoint="0,1">
      <GradientStop Offset="0" Color="Green"/>
      <GradientStop Offset="0.6" Color="Lime"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle><Rectangle Width="98" Height="98" 
         Canvas.Top="1" Canvas.Left="1" 
         RadiusX="14" RadiusY="14">
    <Rectangle.Fill>
      <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
        <GradientStop Offset="0" Color="#FFFFFFFF"/>
        <GradientStop Offset="1" Color="#00000000"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  <TextBlock Name="FifteenPuzzle1_TextBlock_3_2" 
     Canvas.Left="0" Canvas.Top="5" 
     Canvas.ZIndex="1" FontFamily="Verdana" 
     FontSize="70" Text="15" 
     FontWeight="Bold" Cursor="Hand" />
</Canvas>

puzzleRenderMode 设置为 Image 时,为每个拼图块生成的 XAML 如下

<Image Name="FifteenPuzzle1_Cell_15" Canvas.Left="19" 
     Canvas.Top="70" Canvas.ZIndex="3" Width="400" 
     Height="400" Cursor="Hand" Source="Resources/Photo.jpg">
  <Image.Clip>
    <RectangleGeometry Rect="200,300,100,100" 
            RadiusX="15" RadiusY="15">
    </RectangleGeometry>
  </Image.Clip>
  <Image.RenderTransform>
    <TranslateTransform Name="FifteenPuzzle1_Cell_15_Transform" 
             X="0" Y="0" />
  </Image.RenderTransform>
</Image>

用于打乱拼图块的算法非常简单,可能没有真正优化,但似乎运行良好。我只是创建一个介于 1 和 15 之间的随机数,并尝试该移动是否可用。此算法的问题在于,理论上它可能需要很长时间,但根据“大数定律”,它运行得很好。:)

JavaScript 类中最重要的部分是与 Silverlight 的集成。

_renderControl 函数中调用 Silverlight.createObject,它实例化附加到 HTML DIV 的插件。插件实例化后,将调用事件处理程序 _onXamlLoaded,并渲染 XAML 的动态部分。

_renderControl : function()
{
    this.get_element().innerHTML = String.format("<div id='{0}_Content' " + 
            "style='width:{1};height:{2}'></div>", 
            this.get_id(), this.get_width(), this.get_height());
        
    var hostId = String.format("{0}_Host", this.get_id());
    var bounds = Sys.UI.DomElement.getBounds(this._getContentElement());
        
    Silverlight.createObject(this.get_xamlUrl(), this._getContentElement(), hostId, 
    { width:bounds.width.toString(), height:bounds.height.toString(), version:'1.0' },
    { onError:null, onLoad:Function.createDelegate(this, this._onXamlLoaded) }, 
    null);
},

_onXamlLoaded : function(plugIn, userContext, rootElement)
{
    this._plugIn = plugIn;
    this._rootElement = rootElement;
    
    this._renderNumbers();
    this._drawShuffleButton();
},

我将插件和 rootElement 的引用存储在本地 JavaScript 变量中,因为我使用它来动态生成 XAML,方法是使用 createFromXaml。实际上,当我生成拼图块时,我使用了以下代码将其附加到 XAML 的静态部分

var numberElement = this._plugIn.content.createFromXaml(sb.toString(), false);
this._rootElement.children.add(numberElement);

以及以下代码通过名称获取元素并附加鼠标单击事件处理程序

var elementNumber = this._rootElement.findName(String.format("{0}_Cell_{1}", 
                                               this.get_id(), n));
elementNumber.AddEventListener("MouseLeftButtonDown", this._onNumberClick)

关注点

我知道这是一个非常简单的示例,考虑到使用此框架可用的可能性,但它可以帮助开始理解这项技术,并了解将其集成到现有 ASP.NET 应用程序的可能性。

历史

  • 2008 年 5 月 26 日 - 首次发布。
  • 2008 年 5 月 30 日 - 添加了在 NumberImage 之间切换的可能性,并改进了文章详情。
© . All rights reserved.