Wednesday, October 24, 2007

Computer Space 2007

I will be giving a talk at this year's Computer Space event - at 28th of October. The event will be held in Czech Centre Sofia and my presentation is scheduled to start at 14:45. You can also check the whole event schedule here (BG version). I will going to talk about how to build Facebook applications with ASP.NET. The presentation is not ready yet, but the concept of the app that I will build is. It will be called "Can You?". Stay tuned for more information about the event and the app. The slides (if any :) and the source code will be available right after the presentation.

See you there.

P.S.: Vladi Tchalkov will give a presentation about building Silverlight apps right before mine. So be there earlier for Silverlight goodness.

Sunday, October 21, 2007

Building 3D Cube in Silverlight 1.0 using Script#

Silverlight 1.0 is out there in the wild for a couple of months righorse riverht now (otherwise to say this is to use the classic Bulgarian folklore - "Уйде коня в ряката", translated into English - "Went the horse into the river"). Silverlight 1.1 is still in alpha (beta was scheduled for "later this year") and it is not a good idea to go in production with 1.1. So if you want to use Silverlight on your site today, you must constrain yourself to 1.0 and pure JavaScript. This is not true if you are aware what tools are out there for software developers.

Script# - building Silverlight 1.0 applications with C# today

Script# is a "C# compiler that generates JavaScript as its output instead of IL". Yes that's right. You write your code in plain old C# and in the end you have clean and optimized JavaScript code, ready for deployment. The genius behind Script# is Nikhil Kothari, who developed it on his spare time. (it seems that if you work for Microsoft you have a lot of spare time :) As you can see from the diagram below Script# parses the C# files and produce JavaScript. Also the C# compiler is run against the code to verify its correctness.

script#

Leaning Script#

Understanding Script# programming metaphor is not hard, but have some learning curve. Must read is the read me file, which can be found here. The readning is not a couple of pages, but full blown document, which is very well structured (thanks Nikhil :). If you are familiar with both C# and JavaScript the learning process will be painless and you should only familiarize yourself with some of the new concepts that Script# introduces - scriptlets for example. A good way to explorer Script# is to use ultimate number one .NET developer tool - Reflector.

Building the Cube

As stated in the beginning Silverlight 1.0 is the choice if you want to rich enable your site. However there are a lot samples out there that target 1.1. One of these is the 3D Rotating Picture Cube in Iron Python. If you follow the forum thread you will see that the sample gets translated into C# again for 1.1. Actually the source for the sample came from this wonderful flash tutorial, which gives deep explanation about how to apply matrix transforms on objects and in the end has the source for the cube in flash.

Algorithm for the cube

I'm not going to explain the algorithm for displaying the cube. I just copy and paste it from the samples and renamed some of the methods and fields to be more meaningful. I must confess that I have problems with my geometry classes (I wish it was only geometry) this year in university, but finally managed to take them. Enough side talks, lets look at some code.

Code behind the cubeCubeSolution

Again I will leave the matrix transformation stuff for geometry geeks and will concentrate how to use Script# to get things done. First of all you must download Script# from its download page. After installation a couple of new projects will be available in the newly created Script# project group. Note: Script# have 2 modes - one is to output JavaScript code based on Script# core library, other is to output code that targets ASP.NET AJAX framework. First option is better for now, because Script# have more powerful library (in out case we will heavily use the Math object). Ok let's create a project of type "Class library in a web site". In order to use Silverlight object model we should also add a reference to the ssagctrl.dll that comes with the installation. All these starting procedures are well explained in the read me file. All the interesting stuff is in the Cube.cs and CubeScriptlet.cs files.

Cube.cs

Cube class is the main class that do all the logic. Let's look at its constructor:

public Cube(SilverlightControl control, string[] imageUrls, double edgeLength)

{

rotation = new Point3D(0, 0, 0);

this.edgeLength = edgeLength;

this.control = control;

root = (Canvas) control.Content.FindName( "Root" );

root.Width = edgeLength;

root.Height = edgeLength;

InitializeImages( imageUrls );

InitializeEdgePoints();

Rotate( 0, 0 );

}

It takes:

  • SilverlightControl for doing the hooks with the Silverlight plug-in. Note that this Silverlight control has the same API that has the original browser plug-in for Silverlight. Actually for producing it another feature of Script# was used - ability to import 3rd party components and controls as Script# libraries.
  • array of strings that holds the URLs to the images that will be used as faces of the cube
  • edgeLength that show how big should be the cube.

A reference to the Root canvas is obtained using the Silverlight control . This canvas should be present in the XAML file that is used for the initialization of the SilverlightControl (we will look at this in the scriptlet file). Then some initialization operations are performed and finally default rotation is used to put the cube in its default position. Let's look how we initialize the images:

private void InitializeImages( string[] imageUrls )

{

foreach ( string imageUrl in imageUrls )

{

Image image = (Image) control.Content.CreateFromXaml(

string.Format(@"

<Image Width=""{0}"" Height=""{0}"" Source=""{1}"" Visibility=""Collapsed"">

<Image.RenderTransform>

<MatrixTransform Matrix=""1,0,0,1,0,0"" />

</Image.RenderTransform>

</Image>", edgeLength, imageUrl), true);

root.Children.Add( image );

Canvas.SetLeft( image, 0 );

Canvas.SetTop( image, 0 );

}

}

For each url a new instance of type Image is created using the helper method CreateFromXaml(), exposed by the SilverlightControl. Note that this is the only way to create Silverlight 1.0 objects, because they did not have public constructors. When each image is created, it is added to the root canvas and positioned at (0,0). As you can see in the beginning each image won't be visible, because it has its visibility set to collapsed. This is why we call the Rotate() method in the constructor. It is going to apply the correct visibility according to the current position of the cube. Let's look at the Rotate() method itself:

public void Rotate( double offsetX, double offsetY )

{

rotation.X -= offsetY;

rotation.Y += offsetX;

Point[] transformations = CalculateTransformationPoints();

ApplyTransformation( 0, transformations[ 2 ], transformations[ 0 ], transformations[ 3 ] );

ApplyTransformation( 1, transformations[ 5 ], transformations[ 1 ], transformations[ 2 ] );

ApplyTransformation( 2, transformations[ 0 ], transformations[ 2 ], transformations[ 1 ] );

ApplyTransformation( 3, transformations[ 4 ], transformations[ 3 ], transformations[ 0 ] );

ApplyTransformation( 4, transformations[ 3 ], transformations[ 4 ], transformations[ 5 ] );

ApplyTransformation( 5, transformations[ 1 ], transformations[ 5 ], transformations[ 4 ] );

}

Again this is mainly geometry stuff. What is interesting here is the how the offsets are applied to the rotation member. If you have looked closely into the constructor's body you have found that rotation member is of type Point3D - custom class in the solution, which holds the current position of the cube. Finally let's look at the ApplyTransformation() method:

private void ApplyTransformation( int faceIndex, Point a, Point b, Point c )

{

UIElement element = root.Children.GetItem( faceIndex );

element.Visibility = IsFaceVisible(a, b, c) ? Visibility.Visible : Visibility.Collapsed;

if (element.Visibility == Visibility.Visible)

{

MatrixTransform transform = (MatrixTransform) element.RenderTransform;

Matrix matrix = transform.Matrix;

matrix.OffsetX = a.X;

matrix.OffsetY = a.Y;

matrix.M11 = ( b.X - a.X ) / element.Width;

matrix.M12 = ( b.Y - a.Y ) / element.Width;

matrix.M21 = ( c.X - b.X ) / element.Height;

matrix.M22 = ( c.Y - b.Y ) / element.Height;

transform.Matrix = matrix;

}

}

It handles the complex logic for applying the right matrix transform to the item. In case the face should be hidden its visibility is collapsed and the item is not processed.

CubeScriptlet.cs

This file contains the logic for hooking the DOM elements into our newly created Cube class. Let's examine its constructor:

private CubeScriptlet(Dictionary arguments)

{

Application.Current.RegisterDisposableObject( this );

button = new Button( (DOMElement) arguments[ "Button" ] );

button.Click += OnButtonClick;

ControlParameters cubeParameters =

new ControlParameters( (string) arguments[ "MarkupURL" ], (DOMElement) arguments[ "ParentElement" ],

(string) arguments[ "ID" ], (string) arguments[ "CssClass" ] );

cubeParameters.background = "black";

ControlFactory.CreateSilverlight( cubeParameters, OnXamlLoaded, null, arguments );

}

Here you can see the way to create Silverlight plug-in object. It is through the ControlFactory class, which gets a bunch of parameters for initialization. One of them is the url for the XAML markup that we use to find the root canvas in. What is interesting here is the code for initializing our cube class. This code is in a method called OnXamlLoaded(). It is a callback which gets called when the XAML contents are parsed and constructed in memory. Here is the method:

private void OnXamlLoaded(SilverlightControl control, object context)

{

string[] imageUrls = (string[]) Script.Eval( (string)( (Dictionary) context )[ "ImageUrls" ] );

double edgeLength = (double) ( (Dictionary) context )[ "EdgeLength" ];

cube = new Cube( control, imageUrls, edgeLength);

}

You can see that the URLs to the images are passed as one string. As we will see in a minute this string is JavaScript array of strings serialized as JSON. This is why we need to eval it here before passing it to the Cube constructor.

Other interesting part is the handler to a button's click event, which starts and stops the rotating of the cube:

void OnButtonClick(object sender, EventArgs e)

{

if ( intervalToken != 0 )

{

( (InputElement) button.DOMElement ).Value = "Start";

Window.ClearInterval( intervalToken);

intervalToken = 0;

}

else

{

( (InputElement) button.DOMElement ).Value = "Stop";

intervalToken = Window.SetInterval(OnTimer, 50);

}

}

private void OnTimer()

{

cube.Rotate(0.1, 0.1);

}

Note that Script# has a animation framework, which can be used here as well.

Default.aspx

Finally let's look at the chunk of code that we need in our page.

<ssfx:Scriptlet runat="server" ID="scriptlet" PrecompiledScriptlet="Cube.CubeScriptlet"

EnableDebugging="True">

<References>

<ssfx:AssemblyReference Name="sscorlib"></ssfx:AssemblyReference>

<ssfx:AssemblyReference Name="ssfx.Core"></ssfx:AssemblyReference>

<ssfx:AssemblyReference Name="ssfx.UI.Forms"></ssfx:AssemblyReference>

<ssfx:AssemblyReference Name="ssfx.XDAjax"></ssfx:AssemblyReference>

<ssfx:AssemblyReference Name="ssagctrl"></ssfx:AssemblyReference>

<ssfx:AssemblyReference Name="Cube"></ssfx:AssemblyReference>

</References>

<Arguments>

<ssfx:ElementReference ElementID="btnTest" Name="Button"></ssfx:ElementReference>

<ssfx:ElementReference ElementID="cubeContainer" Name="ParentElement"></ssfx:ElementReference>

<ssfx:StringLiteral Value="cubeControl" Name="ID"></ssfx:StringLiteral>

<ssfx:StringLiteral Value="Cube.xaml" Name="MarkupURL"></ssfx:StringLiteral>

<ssfx:StringLiteral Value="root" Name="CssClass"></ssfx:StringLiteral>

<ssfx:StringLiteral Value="[&quot;images/sqeagle.jpg&quot;,&quot;images/sqgorilla.jpg&quot;]" Name="ImageUrls" />

<ssfx:NumericLiteral Value="330" Name="EdgeLength"></ssfx:NumericLiteral>

</Arguments>

</ssfx:Scriptlet>

We are using the Script# server control called Scriptlet that allow us to easily embed our code into the page. You can see here how we pass the array with image URLs as JSON string (for the sake of the sample I have removed the other four pictures from the array, because the string gets big).

So that's it. You can see a action shot bellow and find the download link at the end of the post.

action

Gotchas found during development

  • Cannot create Silverlight objects from code. You can only use the factory method of the Silverlight control, which creates objects from XAML and returns DependencyObject that you should cast to your type. In case you want to create objects that did not derive from DependecyObject it gets complicated. This is way I ended with my own Point class and did not use the Point class from the framework.
  • Using the Scriptlet server control is uncomfortable when your scriptlet is in another assembly. In order to refresh it when you rebuild it, it is required to switch to design mode to remove the reference to your assembly and add it again in the assembly references list of the control.
  • The scriptlet approach is good when you can use the server side control, but when you want to embed just the script there is some extra work.

Hope you will enjoy the sample and start your Silverlight apps today with Script#.

Download the sample solution from here.

P.S.: More translated traditional Bulgarian jokes can be found here.

P.S.S.: For more Silverlight samples with Script # - check Nikhil's carousel series.

Friday, October 19, 2007

Working with TFS offline / disconnected

If you have worked with TFS (stands for Team Foundation Server, not for Tradition Financial Services or Toronto French School) when the server is unavailable (if your server is down or your VPN connection has gone away) you have definitely experienced one thing:

Working with disconnected TFS sucks!

Yep. This is truth and the truth hurts. I have even recently heard developer saying "Fucking TFS. SourceSafe was better. It just worked". I did not want to comment on TFS vs SourceSafe - both hands up for TFS and its atomic change sets. I also did not want to comment on TFS vs Subversion, where Subversion just stand out in disconnected environment. MS are promising that this "mistake" will be fixed in the next version of TFS. But while we are waiting for it I will tell you (you maybe already aware of it already) how to make it less painful.

Team Foundation Power Toys (Tools) - TFS painkiller

Don't hesitate and go straight to the download link. TFPT consist of a bunch of useful tools and additions to TFS. Most interesting is the command line utility - TFPT.exe, which have a bunch of options. What we need is the option online of the tool. Here is sample how to use it:

tfpt.exe online /recursive /delete path_to_folder_with_solution

We need the recursive switch to recursively walk through the directories and search for changes. Delete is required if you have deleted items from the solution. This command will bring a popup windows that will display all actions that you will do. If you did not the window to show you can use the /noprompt switch. If you are uncertain what will happen you can use the preview switch:

tfpt.exe online /preview /noprompt path_to_folder_with_solution

This will show all the modifications that will be done, without actually doing them. Note that if you have renamed files the tool did not catch it. So it may sounds silly but don't rename while disconnected.

You can read more about the tool here and here or in the document that comes with the installation.

Hope this will help you leave the swearing from TFS to some other place. I can think about two or three of those places. What about you?

Thursday, October 18, 2007

Speed up your Vista

Are you using Vista? I mean are you still waiting for the calculation of how long it will take to move these files. Or you have just clicked Windows Key + E and you are headed directly to the kitchen to make a cup of coffee while your windows explorer decides to popup. OK, while waiting I will tell you a way to speed up the things.

Delete your recent network locations

So as simple as it seems deleting your network locations can improve the performance, especially when you are not part of the listed location any more. How to do the operation. Open My Computer (this process may take time :). Find the network locations group at the bottom of the groups displayed. Delete all of them. Note: selecting all locations (in order to delete them) also can take some time.

P.S.: I'm sure that I did not invented this technique, but hope you will find it useful.