|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
![]() IntroductionRecently, I'm interested in a very amazing technology called Silverlight, and I'm trying to learn it because it's very powerful. Actually Silverlight have 2 versions:
For a complete list of differences see here Unfortunately, to easily use Silverlight 2.0 beta1 is necessary Framework 3.5 and Visual Studio 2008 personal or above. My idea is to integrate a Silverlight control into an ASP.NET Ajax control, but it's seem quite difficult without Visual Studio 2008. For this reason I integrated a Silverlight 1.0 control into ASP.NET Ajax control using Visual Studio 2005. BackgroundNormally when I start to learn a new technology I always try to implement a very simple example, but to make all more interesting, normally I implement a complete application or game. When I was a child and there were no computers at home, I spent a bit of my free time playing with a game called Fifteen Puzzle. It's a very simple game but not absolutely easy to solve at the begin. More details about it at this link Then, I implemented it in Silverlight 1.0 integrated into a ASP.NET Ajax control. Using the codeThe solution is divided in the following projects:
In the web application we have just a ASP.NET web form that contains the control and a ScriptManager (the core of ASP.NET Ajax Framework). In the control we have the following files:
The class FifteenPuzzle extends ScriptControl (base class for all ASP.NET Ajax control on server side) and override 2 method:
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;
}
The file Controls.Resources.FifteenPuzzle.js contains the javascript class Controls.FifteenPuzzle the encapsulate most of the logic. The position of each piece of puzzle is contained into a multiple array 4x4. At the begin the array is initialized to the normal order and using javascript I render the pieces dynamically. When the puzzleRenderMode is set to Number the following is the xaml generated for each piece: <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>
When the puzzleRenderMode is set to Image the following is the xaml generated for each piece: <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>
The algorithm used to shuffle the pieces is very easy and probably not really optimized, but seem work fine. I just create a random number between 1 and 15 and try if the move is available. The problem with this algorithm is that in theory it could take long time but for the "Law of large numbers" work fine. :) The most important part of javascript class is the integration with Silverlight. In the _renderControl function is called the Silverlight.createObject that instantiate the plugin attached to one html div. When the plugin is instantiated the event handler _onXamlLoaded is called and the dynamic part of xaml is rendered. _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();
},
I stored the references to plugin and rootElement in local javascript variable because I use it to generate dynamically the xaml using createFromXaml method. Infact when I generate the pieces I used the following code to attach it to the static part of xaml var numberElement = this._plugIn.content.createFromXaml(sb.toString(), false);
this._rootElement.children.add(numberElement);
and the following code to get the element using the name and to attach the event handler on mouse click: var elementNumber = this._rootElement.findName(String.format("{0}_Cell_{1}", this.get_id(), n));
elementNumber.AddEventListener("MouseLeftButtonDown", this._onNumberClick)
Points of InterestI know that this is a very poor example compared with the possibility available with this framework, but it can be useful to start to understand the technology and to understand the possibility to integrate it into an existing ASP.NET application. History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||