Welcome to MSDN Blogs Sign in | Join | Help

Adam Kinney posted all of the Fire Starter videos and the site has a cool Silverlight UI.

firestarter_500

 

I will be speaking at the Silverlight 1.0 Fire Starter event on November 29th along with a bunch of my colleagues. My two sessions are "Media, Markers and More" and "What will Silverlight look like in future versions? WPF".  The first session goes into the gory details of working with Media in Silverlight 1.0. How you can use dynamic and static markers to bring a media experience some spice. And some of the pitfalls to avoid.  The second session is an introduction to programming with WPF and how what we see in WPF today will be reflected in Silverlight tomorrow.   If your interested in attending the check out the invite below!

image

On November 29, 2007 Microsoft will be hosting Silverlight 1.0 Fire Starter on the Redmond, Washington campus. This daylong event is free to anyone who wants to learn about designing and developing with Microsoft Silverlight 1.0.

Microsoft Silverlight 1.0 is a cross platform browser plug-in that enables for easy development of media rich web sites. For more information, visit http://silverlight.net.

November 29, 2007
Microsoft Redmond Campus
1 Microsoft Way
Redmond, WA
Building 33, Kodiak Room
** Please have a photo ID with you to register onsite and park

Check-in:
8:00 am
Event: 8:30 am – 5:00 pm
Register: http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032359153&Culture=en-US
or by calling 1-877-673-8368 and referencing Event ID 1032359153

AGENDA

8:00 am – 8:30 am Breakfast  
8:30 am – 9:00 am Introduction to Silverlight Mithun Dhar
9:00 am – 10:00 am Getting Started with Silverlight Laurence Moroney
10:00 am – 10:15 am Break  
10:15 am – 11:15 am Microsoft Expression Design Tools Arturo Toledo
11:15 am – 12:15 pm XAML Essentials for Silverlight Laurence Moroney
12:15 pm – 1:00 pm Lunch  
1:00 pm – 2:00 pm Developer Tools for Silverlight Adam Kinney
2:00 pm – 3:00 pm Media, Markers and More Ernie Booth
3:00 pm – 3:15 pm Break  
3:15 pm – 4:15 pm Popfly and Silverlight – Writing a Silverlight ‘Social’ app Popfly Team
4:15 pm – 5:00 pm What will Silverlight look like in future versions? WPF Ernie Booth
Post Event Evening event with XBOX, networking and refreshments  
My officemate and friend Laurence Moroney's Silverlight 1.0 book is now available.  Check out his detailed post here: http://blogs.msdn.com/webnext/archive/2007/10/27/introducing-silverlight-1-0-book-is-now-available.aspx

Jamie Cansdale of Test Driven.Net has improved the Reflector Silverlight Add-in and started a community project here.  If you have improvements, bugs, or features request please posted them to the community site.

Jamie changed it so that the C# or VB doesn't get displayed in tabs by defaut as this doesn't scale well for larger projects. You can still digg through the code as the assembly is added to Reflector.  He tested against all the samples on the Silverlight.net Site and found that the add-in didn't scale well for the airplane sample.

Jaime also has done some great work on integrating unit testing with Silverlight .NET that I would suggest checking out.

One of the nice advantages to Silverlight is that you can view the source of a site to see how things work, but with Silverlight 1.1 Alpha that process became more complex.  While you can still fish through the JavaScript and Xaml to find the .NET assembly(dll) that is doing all the logic it takes a lot more time.

Thus I decided to write a plugin for Lutz Roeder's Reflector that takes a URL to a Silverlight page and finds the assembly for that page.  It also loads up the JavaScript and root Xaml for the page.

Download

Here is all the source and assembly for the 0.2 Alpha of the Reflector Silverlight Browser.

Install

To install the plugin:

  1. Put the "Reflector.SilverlightBrowser.dll" file in the same directory as you have Reflector installed. 
  2. Launch Reflector
  3. Choose "View->Add-ins"
  4. Click Add
  5. Choose the Reflector.SilverlightBrowser.dll file.
  6. To test the plugin try the chess game sample from Silverlight.net

Using the Plugin

Once it is installed hit "CRTL+U" or "File->Open Silverlight URL". 

Paste a link to your favorite Silverlight site into the textbox and hit go.

 

Protecting Your Code

So the feedback I get when I tell people about this plugin is how can protect the IP in my code from being seen by other people. I have two pieces of advice on that subject.  First option is to keep the code you want to keep protected on your server and then make webservice calls from your client to that code.

The second option is to use Obfuscation.  What is Obfuscation you say? "In the context of software, obfuscation is the process of scrambling the symbols, code, and data of a program to prevent reverse engineering." - CLR and .NET Security blog.

If you would like to learn more about Obfuscation check out this great post.

Bugs and Features

First off I wrote this in a matter of a day or two with some great guidance from Lutz Roeder so a big thank you to Lutz. Thus there are inevitably going to be a number of bugs in the code.  You have code so feel free to improve it and use it as you like.

The major issue I am going to hear about is that some particular site doesn't work correctly, if you find a site that doesn't work that you would like to have work please send me the link.

Second what features are missing that you would like to see?

Third I would love to hear any other feedback you might have to offer.

Enjoy!

The .NET framework version Silverlight targets is the same that C# 3.0 targets and so we are able to take advantage of the new language features in C# 3.0. The LINQ (Language INtegrated Query) features of C# 3.0 has gotten the most attention of any of the new features, but some of the other features are my favorite additions to the language. I will a link to learning more about LINQ at the end of this post.

Let's start looking at the feature in C# 3.0 by looking at the code listing from my previous post.  Here it is as I wrote it:

C# without 3.0 Features

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ManagedSilverlight101
{
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();

            parentCanvas = (Canvas)FindName("parentCanvas");

            this.ParentCanvas.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));

            Ellipse childShape = new Ellipse();

            childShape.Width = 100;
            childShape.Height = 100;

            LinearGradientBrush lgb = new LinearGradientBrush();

            GradientStop gs1 = new GradientStop();
            gs1.Color = Color.FromRgb(0, 0, 255);
            lgb.GradientStops.Add(gs1);

            GradientStop gs2 = new GradientStop();
            gs2.Color = Color.FromRgb(0, 255, 0);
            gs2.Offset = 1;
            lgb.GradientStops.Add(gs2);

            childShape.Fill = lgb;

            this.parentCanvas.Children.Add(childShape);
        }

        private Canvas parentCanvas;

        public Canvas ParentCanvas
        {
            get { return parentCanvas; }
            set { parentCanvas = value; }
        }
    }
}

There is nothing particularly special about the previous code listing, but a few item's to notice. First in the Page_Loaded method it is difficult to descern what the intent of the programmer was.  Unlike Xaml where everything is declarative the code above is very procedural. All that is happening of course is that the program is displaying a red rectangle containing a small circle with a blue to green gradient color.  Something like this:

Result

This was so non obvious from the code above I original thought we were trying to display a red rectangle containing a smaller rectangle with a blue to green gradient color.  My eyes scanned the program above and failed to notice that the code was creating and Ellipse instead of a rectangle.

If had tried to achieve this same result with xaml the code would look this this:

<Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Loaded="Page_Loaded" 
        x:Class="ManagedSilverlight101.Page;assembly=ClientBin/ManagedSilverlight101.dll"
        Width="640"
        Height="480"
        Background="Red"
        >
  <Ellipse Width="100" Height="100">
    <Ellipse.Fill>
      <LinearGradientBrush>
        <GradientStop Color="Blue"/>
        <GradientStop Color="Green" Offset="1"/>
      </LinearGradientBrush>
    </Ellipse.Fill>
  </Ellipse>
</Canvas>

This is much easier to quickly read and understand what the program will do. The problem of course is that often times we don't have the ability to statically define our display because of the dynamic nature of a given program. This is where the features in C# 3.0 come into play.  Below is a code listing that I have transformed from our original code to instead use the new features of the language.

C# 3.0 Style

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace ManagedSilverlight101
{
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();

            this.ParentCanvas = (Canvas)FindName("parentCanvas");

            this.ParentCanvas.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));

            var stops = new GradientStopCollection { 
                            new GradientStop { Color = Color.FromRgb(0, 0, 255) },
                            new GradientStop { Color = Color.FromRgb(0, 255, 0), Offset = 1 } };

            var lgb = new LinearGradientBrush() { GradientStops = stops };

            var childShape = new Ellipse { Width = 100, Height = 100, Fill = lgb };

            this.ParentCanvas.Children.Add(childShape);                
        }
        public Canvas ParentCanvas { get; set; }   
    }
}

We have reduced the length of our program and increased it's readability. It in fact is very declarative like the Xaml. Let's examine the new features of C# 3.0 I am using in this example.  First after the call to the method InitializeComponent we are assigning the property ParentCanvas from the result of the FindName.  This code on it's own isn't any different, but if our eyes scan to the bottom of the Page class we have the line:

public Canvas ParentCanvas { get; set; }

This line is defining a new property named Canvas. Notice that we didn't have to create a separate field to hold the data that is being set by the ParentCanvas property.  This is a great shortcut to creating properties which is a good programming practice since in the feature we can change how the data is stored or retrieved without breaking the Page interface.

The next change to our program is the statement:

var stops = new GradientStopCollection { new GradientStop { Color = Color.FromRgb(0, 0, 255) },
                                                                   new GradientStop { Color = Color.FromRgb(0, 255, 0), Offset = 1 } };

Implicitly Typed Local Variables

This is using a few new features of C#. The first is this part of the statement:

var stops = new GradientStopCollection

We are creating a variable named stops which is of type GradientStopCollection.  It is often cumbersome to write the name of the type on both sides of an assignment statement. By placing the var keyword before the name of our variable we are telling the compiler to infer the type information for stops from the type on the right hand side of the assignment operation.  In this case a GradientStopCollection. 

Unlike JavaScript or other loosely typed languages the local variable stops is strongly typed.  Indeed if we were to say something like this after the creating of the stops variable:

 stops = "Hello";

The compiler will throw the error: Cannot implicitly convert type 'string' to 'System.Windows.Media.GradientStopCollection'.  This is because stops is in fact an instance of a GradientStopCollection. The var keyword is simply a shorthand convenience.

Collection Initializers

The next C# feature is in this part of that statement:

new GradientStopCollection { ... };

It is creating a new GradientStopCollection and then calling Add() passing each element in between the curly braces.  A simpler example looks like this:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

and is semantically the same as this code:

 List<int> digits = new List<int>();
            
 digits.Add(0);
 digits.Add(1);
 digits.Add(2);
 digits.Add(3);
 digits.Add(4);
 digits.Add(5);
 digits.Add(6);
 digits.Add(7);
 digits.Add(8);
 digits.Add(9);

And if fact this is what the compiler is generating for us when we use this syntax.  It is called a collection initializer is a natural extension to how we were already able to assign items to an array:

int [] digits = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Object Initializers

The last new feature in that same statement applies to the elements we are adding to the collection:

new GradientStop { Color = Color.FromRgb(0, 0, 255) }, 
new GradientStop { Color = Color.FromRgb(0, 255, 0), Offset = 1 }

Here we are using a feature called Object Initializers. Just like a Collection Initializers we are using a curly brace instead of a parentheses after:

new GradientStop {

Then we are have some code that looks like this:

Color = Color.FromRgb(0, 255, 0), Offset = 1

If this looks like property assignment that's because it is.  We are simply setting the Color and Offset properties of the GradientStop objects we are creating. That produces much cleaner code then the alternative syntax:

GradientStop gs2 = new GradientStop(); gs2.Color = Color.FromRgb(0, 255, 0); gs2.Offset = 1;

In fact when we combine all three of those features into one statement we are left much easier to read code:

var stops = new GradientStopCollection { new GradientStop { Color = Color.FromRgb(0, 0, 255) },
                                                                   new GradientStop { Color = Color.FromRgb(0, 255, 0), Offset = 1 } };

Compared to:

LinearGradientBrush lgb = new LinearGradientBrush();

GradientStop gs1 = new GradientStop();
gs1.Color = Color.FromRgb(0, 0, 255);
lgb.GradientStops.Add(gs1);

GradientStop gs2 = new GradientStop();
gs2.Color = Color.FromRgb(0, 255, 0);
gs2.Offset = 1;
lgb.GradientStops.Add(gs2);

Also notice that we didn't have come up with local variable names for our GradientStops.  Which also makes for easier to maintain code.

The last two changes to our program are just making use of the same new C# features described above:

var lgb = new LinearGradientBrush() { GradientStops = stops };

var childShape = new Ellipse { Width = 100, Height = 100, Fill = lgb };

 

Conclusion

As you have seen some of the new features is C# 3.0 make code much more readable and hopefully maintainable. There are a lot of other exciting features in both C# and VB thanks to LINQ. If you are interested in learning about all other great new features check out this great MSDN article on LINQ by Anders Hejlsberg and Don Box.

To begin our .NET Silverlight learning we will start off with an overview of .NET. For those are used to developing Silverlight applications with JavaScript, we will be concentrating on the differences between using JavaScript and .NET.  If you haven't written a Silverlight application before this will also be a good introduction to using .NET.  If .NET is old hat for you by now then most of this will be review, but there are still some important differences with regard to how Silverlight works compared to WPF (Windows Presentation Foundation).

Why .NET?

A question that often comes up when we talk about .NET and Silverlight is why do we need .NET when JavaScript has already proven it's self as a great way to develop web applications.  Four reasons spring to mind right way. 

Consistency is the first reason compared to JavaScript, not in the core EcmaScript it's self, but more on the DOM side or how we access the page elements.  For each browser the DOM is different and only an experienced web developer knows how to write code that works well in all browsers.  With Silverlight we bypass most of this problem as we are targeting XAML and the Silverlight object model instead of the browsers object model. The other part of this problem is that when you are using JavaScript you are relying on each browser's implementation of the JavaScript execution engine.  This is where .NET differs.  When we write a .NET application it is the Silverlight plugin which handles the execution of our code so there are no differences from one browser to the next. It is the same on Mac, Windows, Firefox, Safari and IE!

Performance is a great reason to use .NET over JavaScript.  Scott Guthrie had a great demonstration in his MIX keynote which showed off a chess game which implemented chess algorithms.  Once in JavaScript and once with .NET.  The performance comparison between the two was staggering.

Type Safety is one that rings home with me.  I love the fact that when I compile I get feedback that my code is wrong and I have a chance to fix my mistakes before running the application. While Type Safety is great there are a lot of features in JavaScript which I have grown to enjoy. C# 3.0 has some new language features such as local type inferencing, anonymous types, extension methods and type intializers which allow for quick development similar to JavaScript while maintaining Type Safety.  We will get to some of those features a bit later.

.NET Framework is the most compelling reason to use .NET.  The framework is a collection of libraries for a variety of tasks, from UI development to security and networking. While the Silverlight version of the .NET framework is much smaller then the full .NET Framework it can still be a lot to learn. I remember when I first started with .NET back in 2000 I would write some code to do x and then later I would discover that there was already a class which did x.  Since then a lot has been written so we can search to see what libraries we can use, but there is still no replacement for discovering all that the .NET Framework has to offer.

There are a bunch of other reasons to use .NET like the support for multiple language 37 at last count including, IronPython, IronRuby, JavaScript, Cobal, PHP, C#, VB, C++\CLI, Ada, Boo, Chrome, Eiffel, Forth, FORTRAN, Haskell and many more. Here is a a more complete list.

Desktop .NET vs. Silveright .NET

There are a few differences between the full .NET Framework and the version that ships with Silverlight 1.1 Alpha.

Cross Platform, Cross Browser is very important to Silverlight and so just like the rest of Silverlight the .NET components will work on Mac and Windows.  They will also run in FireFox, IE and Safari.  There is no difference between the framework when running on different platforms.

Size of the Silverlight .NET version is about 4 MBs in the 1.1 Alpha.  This is significantly smaller then the full framework which is around 50 MBs.  In order to maximize user experience the size and install time were greatly reduced so that users with out Silverlight can still be targeted by Silverlight web sites.

Sandbox model is a way to provide full .NET applications in Silverlight without having to prompt users for install.  It provides a safe way to run applications, but has a few restrictions.  There is limited file access, so that you can't just start enumerating the files on a users machine. Networking support, no socket support. No elevation prompts and no ability to escape the sandbox.

 

Getting Started

The first place to start is to define what is required to create a .NET Silverlight application.  There are four basic ingredients in any Silverlight 1.1 program:

  1. An html file to hose our Silverlight plugin with.
  2. JavaScript files which load the plugin with the appropriate settings such as Height, Width and Windowless.
  3. A XAML file which defines the look of our root page and more importantly points at our .NET code to run.
  4. .NET Assembly (dll) which houses all of the logic from our .NET code.

 

What you need to Install

  1. Silverlight 1.1 Alpha
  2. Visual Studio "Orcas" Beta 1
  3. Silverlight Tools for Visual Studio "Orcas" Beta 1

 

Creating a New Silverlight .NET project in Visual Studio

Now that you have everything installed lets start by having visual studio create a project for us.

Open Visual Studio "Orcas". 

NOTE: If this is the first time you have opened Visual Studio you will be prompted to choose which setup you want, C#, VB, C++, etc.  This simple configures menus, and toolbar layout, it doesn't restrict you from creating projects with the other languages.

  1. From the menu choose File->New->Project (CRTL+SHIFT+N)
  2. In the Dialog that pops up expand the Visual C# node and choose the Silverlight node.
  3. Make sure the Silverlight Project is highlighted.
  4. In the name field at the bottom of the dialog write "ManagedSilverlight101"
  5. Click OK

Visual Studio will create a project containing a number of files for us. On the right in Visual Studio our Solution Explorer should look like the image below:

We will start exploring each of the files to see what our Silverlight project is made of.  We will begin with TestPage.htm. Double click it in the solution explorer and it will open in Visual Studio.

TestPage.htm

Here are the contents of our html file:

<html xmlns="http://www.w3.org/1999/xhtml">
<!-- saved from url=(0014)about:internet -->
<head>
<title>Silverlight Project Test Page </title>
<script type="text/javascript" src="Silverlight.js" mce_src="Silverlight.js"></script>
<script type="text/javascript" src="TestPage.html.js" mce_src="TestPage.html.js"></script>

</head>

<!-- Give the keyboard focus to the Silverlight control by default -->
<body onload="document.getElementById('SilverlightControl').focus()">
<div id="SilverlightControlHost" >
<script type="text/javascript">
createSilverlight();
</script>

</div>
</body>
</html>

This is a very simple test page and there are only a few tags which we care about on this page.  The first is the two script tags which point to Silverlight.js and TestPage.html.js.  The first is a file we will include in every Silverlight application we write.  It contains functions to detect if Silverlight is installed and give us information about version.  It also contains two functions createObject() and createObjectEx() which we will call create the Silverlight plugin on our page.

The other part of this page which is important to note is the call createSilverlight(); which is calling a method in TestPage.html.js.

Silverlight.js and TestPage.html.js

Now open TestPage.html.js from the Solution Explorer.  You might have to expand the TestPage.html file by clicking on the plus symbol. Below is the code listing from TestPage.html.js:

function createSilverlight()
{
    Sys.Silverlight.createObjectEx({
    source: "Page.xaml",
    parentElement: document.getElementById("SilverlightControlHost"),
    id: "SilverlightControl",
   

    properties: {
        width: "100%",
        height: "100%",
        version: "0.95",
        enableHtmlAccess: true
        },
        events: {}
    });
}

As you can see the only function in the JavaScript file is createSilverlight().  This function is just calling a function Sys.Silverlight.createobjectEx() which is found in the Silverlight.js file.  The two important items to note for now are the source paramter which is set to Page.xaml and the parentElement parameter which is being set to the result of document.getElementById("SilverlightControlHost").  It is important to make sure that the name passed into getElementById here matches the id of our div in our html file.  Both are highlighted in green above. 

The Page.xaml file is the name of the file where all our XAML exists. This is the first page which the Silverlight plugin will load after the call to createObjectEx.

XAML

Xaml (extensible Application Markup Language) is an XML language which describes our user interface. Open the Page.xaml file by double clicking on it in the Solution Explorer.  Below is the Xaml in Page.xaml:

<Canvas x:Name="parentCanvas"
xmlns="
http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Page_Loaded"
x:Class="ManagedSilverlight101.Page;assembly=ClientBin/ManagedSilverlight101.dll"
Width="640"
Height="480"
Background="White"
>

</Canvas>

We have a single element a Canvas which has a width of 640 and a height of 480. There are two important attributes to observer in the Xaml.  The first is the Loaded attribute which simply sets the Loaded event to a method called Page_Loaded. 

The second attribute and the one that says we are using .NET vs. JavaScript is the x:Class attribute.  Let's break apart the the statement that is being assigned to x:Class. 

ManagedSilverlight101.Page specifies that the class we want to load is called Page which is in the ManagedSilverlight101 namespace. We will look at the code in a minute. 

assembly=ClientBin/ManagedSilverlight101.dll says that the Page class in the namespace ManagedSilverlight101 is stored in the ManagedSilverlight101.dll which is located in a relative directory called ClientBin.

As a review a dll is just a file which stores code.  However instead of storing it as text the compiler has transformed the code into an intermediate language called MSIL (Microsoft Intermediate Language).  The reason we compile the code is so that we can guarantee the programmer didn't make any typing mistakes while writing the program.  In .NET we call the dll files assemblies.

For those familiar with WPF a big difference between Silverlight and WPF is that Xaml is never compiled, only our .NET code gets compiled.  However we may still store the Xaml as an embedded resource in the dll.

.NET Code

Now open the Page.xaml.cs file from the solution explorer.  You might have to expand Page.xaml by clicking on the plus sign to find the Page.xaml.cs file below it. Here is the code from the Page.xaml.cs file:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ManagedSilverlight101
{
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
           // Required to initialize variables
           InitializeComponent();
        }
    }
}

All of the code above is written in the language C# which has very similar syntax to JavaScript. I am not going to go into the details of C# here, but I will cover enough to explain what is happening in our small program. I have intentionally left out details to make understanding simpler. I would suggest picking up a good C# book if you are interested in learning more about the language or pickup a book on your favorite .NET language.  There is a new JavaScript implementation that the DLR (Dynamic Language Runtime) team is working on which can also be used to write .NET programs.

At the top of the code we have nine lines which all start with the word "using" followed by something like System.Windows.Ink.  These statements are just saying that we want to use the classes in those namespaces. Namespaces allow us to scope classes, methods and variables. It is very similar to using a script tag to import other JavaScript files that you are using, except that we don't have to import everything defined in the file, only the parts we care about.

Then we have lines of code like this:

namespace ManagedSilverlight101

{

This simple says that we want to create all the code contained in the curly braces in the ManagedSilverlight101 namespace.

Next we have the lines:

public partial class Page : Canvas
{

Here we are creating a new class named Page which derives from the class Canvas.  This means our Page class will take on all the properties, methods, fields and events of the Canvas class and then we can add new behavior and data to the Page class to make it do what we want. Classes are similar to JavaScript prototypes.

Now we have the lines:

public void Page_Loaded(object o, EventArgs e)
{

With this line we are defining a function called Page_Loaded that takes two parameters.  C# requires parameters to be typed. The first parameter is called o and is of Type object.  object is the base type of every other type in .NET so any type could be passed into the Page_loaded function.  The second parameter is called e and is of type EventArgs.

The Page_Loaded function is actually an event handler.  If you remember that in our Xaml we defined an event handler for the Loaded event to be "Page_Loaded".

The final part of our small program is:

InitializeComponent();

This is just a call to the function InitalizeComponents(). Currently this method doesn't do anything, but if you put the cursor on the method and right click you will get a context menu.  Then choose "Go To Definition" and Visual Studio will open a new file.

 

The file is called Page.g.cs and is generated by Visual Studio on our behalf.  Here are the contents of the file:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ManagedSilverlight101
{
    public partial class Page
    {
        // variable declarations
        private void InitializeComponent()
        {
        }
    }
}

As you can see this looks very similar to our class defined in Page.xaml.cs. In fact it has the same namespace and class name.  This is because it is actually the same class we were defining in the Page.xaml.cs file, except that there is an additional function declared called InitializeComponent(). The partial keyword before the class keyword tells the compiler that we want to extend the other class we are defining in another file, not create a new class. Partial classes are owned by the designer (which we don't yet have with Silverlight) and by the compiler when we update our xaml file. It is a place where generated code can be put without messing up code written by programmers.  Most of the time we aren't going to need to look at this file and we will almost never have to edit it, so close that tab by clicking on the X at the top, right of the tab page.

 

Creating Visual Elements with Code

Now that we have a grasp of what Visual Studio created for us we can start writing code.  So switch or open the file Page.xaml.cs.

Xaml to .NET

After the Page_Loaded function definition we are going to add a property to hold the root element of our Xaml file. Start by typing in lowercase: 

prop

And then hit TAB twice.  The first time closes the intellesense that popped up when we typed prop and the second time will create a code snippet for us. Notice that the work int is highlighted with a blue background:

Now type the word Canvas with the uppercase C.  C# like JavaScript is a type sensitive language. 

Press the TAB key twice again and myVar will become highlighted in blue. Notice that when you hit TAB that Canvas changed not only where you typed it but also before the work MyProperty. Now we will finish off the property by naming it:

Type: parentCanvas

Press TAB once:

Type: ParentCanvas

Press: Enter

When you hit Enter your cursor will be placed after the property we just created.  It should be defined like this:

 

private Canvas parentCanvas;

public Canvas ParentCanvas
{
    get { return parentCanvas; }
    set { parentCanvas = value; }
}

Now that we have a property to hold our root Xaml element we need to pull the element out of the Xaml and assign it to our new property.

NOTE: In WPF the compiler generates properties for any element you name in Xaml.  Currently you must create and wire up the properties yourself.

In the Page_Loaded function after the InitializeComponent function call add the line:

parentCanvas = (Canvas)FindName("parentCanvas");

This line of code calls the FindName method passing the name of the root element in the xaml file.  In this case we named our property the same as what we named the root element.  This is not required but is a good practice. Then it assigns the result to the parentCanvas field we created when we defined the ParentCanvas property.

Because .NET is typesafe we need to add (Canvas) just before the FindName function.  This bit of code casts what is returned from FindName to the type Canvas. FindName is defined in the class DependencyObject to return the type DependencyObject. DependencyObject is the base type for most everything in Silverlight including the Canvas we declared in our Xaml file, so we are able to cast back to Canvas.

This

Now that we know how to use FindName I am going to introduce a great shortcut.  We don't actually need to call FindName most of the time. The compiler and framework will take care of creating the properties for us.  Remove the lines:

private Canvas parentCanvas;

public Canvas ParentCanvas
{
    get { return parentCanvas; }
    set { parentCanvas = value; }
}

and

parentCanvas = (Canvas)FindName("parentCanvas");

We instead are going to access the parentCanvas through the keywork this.  By placing the x:Class tag in our xaml page we told the compiler that we wanted it to link that xaml snippet to our class.  "this" meaning the current object we are dealing with.  In this case the Canvas that is our root element on our xaml file. So this is evaluates to true:

this == (Canvas)FindName("parentCanvas");

Now we can start manipulating the parentCanvas by changing it's properties and adding children.

Manipulating Properties

The first place to start exploring is to play with the properties of our parentCanvas. We will start by changing the background brush. Where we had:

parentCanvas = (Canvas)FindName("parentCanvas");

Put this line:

this.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));

The line of code above sets the Background of our Canvas to the SolidColor Red. We start by creating a new SolidColorBrush and pass the color we want to assign in the constructor.  To pass the color we are using the Color classes static method FromRgb. Which takes three arguments of red, green and blue values which range from 0 to 255. In this case we are getting the red color.

We also can access the colors through named colors like this:

this.Background = new SolidColorBrush(Colors.Red));

Now that we have added that we should run our project to see our result. 

Press: CRTL+F5

The project will build and then open the default browser to display our Silverlight application. If something was mistyped you will get build errors. While errors can be frustrating to fix they are a lot more convenient then discovering the issues at runtime.

Adding Children

For the finaly we will add children to our parentCanvas programmatically. We are going to add an Ellipse that has a gradient brush that fades from Blue to Green.  We are going to put this on the line after:

this.Background = new SolidColorBrush(Color.FromRgb(255, 0, 0));

Here is the code listing:

Ellipse childShape = new Ellipse();

childShape.Width = 100;
childShape.Height = 100;

LinearGradientBrush lgb = new LinearGradientBrush();

GradientStop gs1 = new GradientStop();
gs1.Color = Color.FromRgb(0, 0, 255);
lgb.GradientStops.Add(gs1);

GradientStop gs2 = new GradientStop();
gs2.Color = Color.FromRgb(0, 255, 0);
gs2.Offset = 1;
lgb.GradientStops.Add(gs2);

childShape.Fill = lgb;

this.Children.Add(childShape);

Let's breakdown what is happening here as it is a lot of code. To start we are creating an Ellipse called childShape.  Then we are setting withe Width and Height to 100.  Next we create the LinearGradientBrush called lgb that we are going to paint our Ellipse with.  We great two GradientStop objects and set there Color and Offset properties. This should look very similar to what we did above except that we aren't using a SolidColorBrush. 

We have a line after each of our GradientStop declarations that looks like this:

lgb.GradientStops.Add(gs1);

Here we are adding the gradient stop to the linear gradient brush we defined as lgb.

Then we assign the ChildShape's Fill property our linear gradient brush we just created.

Lastly we call:

this.parentCanvas.Children.Add(childShape);

Which adds our ellipse to the Children collection of the parentCanvas.

Conclusions

We have covered a lot of information in this post, but it is a great foundation for writing future applications.  In my next post I will show how the new features of C# 3.0 can make this code a lot simpler.

This week we launched Silverlight at MIX07 and now all the sessions are online at sessions.visitmix.com.  I am watching a great session on LINQ and Silverlight presented by Anders Hejlsberg. LINQ is only one part of the announcements we made this week at MIX.  We also announced that we have support for .NET with Silverlight. I have been waiting for this announcement for some time as I am much more of a .NET programmer then JavaScript.  Over the next few months I will transform my blog to concentrate on Silverlight with .NET.   At the end of the May I will be presenting in Italy and Sweden on Silverlight and .NET, but more about that later.

It is important to understand the different versions of Silverlight currently available:

Silverlight 1.0 Beta: At MIX the Silverlight Beta 1.0 was released.  It contains support for JavaScript based programming.  While I will not be spending a lot of time writing about that here I will be covering a lot of the same APIs.

Silverlight 1.1 Alpha: At MIX we also released the Silverlight Alpha 1.1.  This version supports both JavaScript based programming and .NET.  Additionally it supports the DLR (Dynamic Language Runtime).  Being a language geek I will be spending some time talking about Iron Ruby and Iron Python. In order to follow the samples on my blog for Silverlight you will need the 1.1 Alpha plugin.

 All the bits, samples, video tutorials, and more can be found on Silverlight.net

A few weeks ago I headed over to Gamefest when XNA Express was announced to shoot a Channel9 video with the team.  Check it out.

For those of you not familiar with XNA Express it allows developers to write games using C# and play them on Xbox 360 and Windows.  XNA is built on top of DirectX 9 and makes writing games a lot easier.

Today we are going to look at a few different methods.  The first set of methods allows us to register a PNRP name and the next set of methods allows us to resolve a PNRP name.  A few important things to keep in mind are that the Windows Firewall Client will block traffic so this code will not work between machines unless we add and exception to the Windows Firewall client.  For now you can manually add the exception or work between two instances running on the same machine. PNRP will not resolve a name registered in the same process, so you need to run two separate instances to make PNRP work.  We will come back to the Windows Firewall problem in a feature post when we look at those APIs.

In my last post I talked about the libs and header files required to compile so reference that post if you are having problems.

 

Most of the peer to peer APIs are exposed as native Win32 libraries.  This means we either have to use PINVOKE or write a C++\CLI 2005 wrapper.  I have chosen to write a wrapper, because the peer to peer APIs require special methods to release the memory from the structures they create.  If you are new to writing interop code you should get a copy of “.Net and Com The Complete Interoperability Guide” by Adam Nathan.

 

For a deep understanding of how PNRP works under the covers check out this article.  Here is the code for the register method. We begin by looking a method that allows us to register a PNRP name.  PNRP is a “DNS-like” protocol accept that it is server-less.  Something to keep in mind is I have removed all error checking from this sample to make it easier to understand.

 

HRESULT P2PCom::Peer::PnrpRegister(PWSTR pwzName)

{

      ULONG                       cAddresses = 0;

 

      HRESULT                     hr = S_OK;

     

      // Address locals

      ULONG pcAddresses =     PEER_PNRP_AUTO_ADDRESSES;

      PWSTR pwzPeerName =     NULL;

      PEER_PNRP_REGISTRATION_INFO info;

      HANDLE registration;

     

ZeroMemory(&info, sizeof(PEER_PNRP_REGISTRATION_INFO));

     

      // Create the peer name.

      hr = PeerCreatePeerName(NULL, pwzName, &pwzPeerName);

     

// We need the cloudName and address to register the PNRP name.

      info.pwzCloudName = L"Global_";

      info.cAddresses = pcAddresses;     

           

      // Register the PNRP name in the cloud.

      hr = PeerPnrpRegister(pwzPeerName, &info, &registration);

     

// Clean up

      PeerFreeData(pwzPeerName);

     

      return hr;

}

Breaking down the PnrpRegister method we first call the PeerCreatePeerName function which creates a PNRP name from the string that is passed into the method.  We passed NULL to the first method because we want to create an unsecured PNRP name.  If we wanted to have a secured name then we would have to pass the results from a call to PeerIdentityCreate fuction.  The article I pointed to earlier will explain the difference between secured and unsecured PNRP names in detail, but basically an unsecure name is not unique a secured name is unique. We passed Ernie into this method we would get 0.Ernie as a result of the call to PeerCreatePeerName. The zero dot in front of Ernie means this is an unsecured peername a secured PNRP name would have a long hash of a public key infront of it.  

Next we assign the name of the cloud we want to register the PNRP name in to a PEER_PNRP_REGISTRATION_INFO structure called info.  In this case we are registering in the global cloud which means the internet.  There are other options for clouds shown in the table below from the Windows SDK:

 

Value

Meaning

PNRP_SCOPE_ANY
0

All IP addresses are allowed to register with the PNRP cloud.

PNRP_GLOBAL_SCOPE
1

The scope is global; all valid IP addresses are allowed to register with the PNRP cloud.

PNRP_SITE_LOCAL_SCOPE
2

The scope is site-local; only IP addresses defined for the site are allowed to register with the PNRP cloud.

PNRP_LINK_LOCAL_SCOPE
3

The scope is link-local; only IP addresses defined for the local area network are allowed to register with the PNRP cloud.

 

The other field of the structure we specifiy is cAddresses which we set to PEER_PNRP_AUTO_ADDRESSES. This tells  PeerPnrpRegister how to bind our PNRP name to our IP address.  Last we call PeerPnrpRegister which actually does the PNRP name registration.

The method below is the .NET wrapper method to expose the native method we just looked at.  It simply marshals the name that is passed in and calls the native PnrpRegister method.

void P2PCom::Peer::RegisterName(System::String ^name)

{

      System::IntPtr ^piName = Marshal::StringToBSTR(name);

 

      PWSTR pName = (PWSTR)piName->ToPointer();

       

      PnrpRegister(pName);

 

      Marshal::FreeBSTR(*piName);

}

Now that we have registered a name we need to resolve the name.  IMPORTANT: you cannot resolve a PNRP name register in the same process you are doing the resolve in, this is a big gotchya when first developing with this API.  Take a look at the source code listing then we discuss what is happening here.

IPAddress ^P2PCom::Peer::ResolvePeerNameCommand(PCWSTR pwzName)

{

      HRESULT                 hr = S_OK;

      PPEER_PNRP_ENDPOINT_INFO pEndpointInfo = NULL;

      ULONG                   cEndpoints = MAX_ENDPOINTS_TO_RESOLVE;

 

      // Perform a synchronous resolve

      hr = PeerPnrpResolve(pwzName, L"Global_", &cEndpoints, &pEndpointInfo);

     

if(pEndpointInfo == NULL)

      {

            return IPAddress::None;

      }

     

      WCHAR   wzAddr[MAX_PEERNAME_LENGTH];     

 

      // Display associated addresses

      for (int i = 0; i < pEndpointInfo->cAddresses; i++)

      {

            DWORD dwLen = (sizeof(wzAddr) / sizeof(wzAddr[0]));

           

            // Make sure the address is IPv6

            if(pEndpointInfo->ppAddresses[i]->sa_family == AF_INET6)

            {

 

                  hr = WSAAddressToString(

                (LPSOCKADDR) pEndpointInfo->ppAddresses[i],

                sizeof(SOCKADDR_IN6), NULL, wzAddr, &dwLen);

            }

      }

 

// Release resources.

PeerFreeData(pEndpointInfo);

 

      IPAddress ^ip = IPAddress::Parse(gcnew System::String(wzAddr));

 

    return ip;

}

We only make one P2P PNRP API call in this method to PeerPnrpResolve which attempts to do a sycronous resolve of the method.  There are also async versions of this method which make sense to use in GUI applications as this method can takes a few seconds to return.  It will return all the pnrp end points it found in the pEndpointInfo argument. That is end points plural because I could register the same end point at work, home and on my laptop, also with unsecure names there will likely be other people with the same end point name as mine.

Next check to see if we received any end points and then loop through all the end points we received.  We only care about those addresses that are IPv6 for this sample.  Change the last endpoint into a string and save it in the wzAddr variable using a WinSock helper method. Then we create a managed IPAddress by calling it’s Parse method on the address string. 

Last thing is to write a wrapper method so that .NET applications can call this method.

System::Net::IPAddress ^P2PCom::Peer::ResolveName(System::String ^name)

{

      System::IntPtr ^piName = Marshal::StringToBSTR(name);

 

      PWSTR pName = (PWSTR)piName->ToPointer();

     

      IPAddress ^ip = ResolvePeerNameCommand((PWSTR)pName);

 

      Marshal::FreeBSTR(*piName);

     

      return ip;

}

In my full class I move all the start up an shutdown code to my constructor and destructor as shown here:

P2PCom::Peer::Peer()

{

      PeerPnrpStartup(PNRP_VERSION);

}

 

P2PCom::Peer::~Peer()

{

      PeerPnrpShutdown();

}

There is a lot more to PNRP and there is a great sample in the SDK located here:

“C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\NetDs\PeerToPeer\PNRP”

 

This week we are going to start exploring the peer to peer (p2p) in Windows Vista.  Before we get into any code an overview of the p2p APIs available in Windows Vista  is in order.

PNRP (Peer Name Resolution Protocol) is like server-less DNS.  It allows clients to register secured and unsecured peer names that can be resolved over the internet.  Currently large data centers are required to host services that PNRP has the potential to replace.  PNRP gives people the ability to discover a friend and see their presence online and then play a game or work on a project together.

PNM (People Near Me) allows for dynamic discovery and invitation of computers running Windows Vista on the same subnet or Ad-hoc wireless.  This means you can play games with people in the airport, swap photos with your friends or collaborate with colleagues. For example Windows Meeting Space uses PNM.

Peer Naming API allows email providers to tie PNRP names to email addresses.  Then any program that uses the WinSock APIs can resolve registered email addressesThis means you can literally ping a friend or put their email address where you would have to put an IP address in a game.

Graphing is a mesh networking API.  It allows groups of people to share information and collaborateA game could create a mesh of online players so that it could do server-less match making. Or an evangelism team could collaborate on a document without having to upload the latest copy to a server.

Grouping is the security component of Graphing.  It allows for a group to be administrated, so that membership and permissions can be restricted.  Think of Grouping and Graphing as a database in the cloud.

Peer Channel is the only managed API in the P2P API suite.  It allows for mesh replication instead of mesh collaboration.

Application Invite (AppInvite) allows a user to invite another user to use a collaboration application.  Any application can register with the invite API and when a user sends an invite to use that application the application will be launched by Windows Vista.  Windows Meeting Space is an example of an application that uses AppInvite.

Contacts API allows the creation and administration of p2p contacts.

Serverless Presence:  Gets contact presence information.

Now that we know what peer to peer offers let’s look at an example of how to use one of these APIs. A few weeks ago I did a video to explain why developers and end users should care about peer to peer.  As a part of that video there was an explanation of how PNRP works. Luckily calling the PNRP API doesn’t require understanding how the resolution works.

We will start our p2p adventure off with the People Near Me API.  Most of the p2p API is Win32 and doesn’t lend its self well to being called through interop from managed code.  So I will be writing all the examples in C++\CLI 2005 which will allow me to expose the APIs through a nice managed wrapper, which will make calling the API possible from .NET.

Our PNM sample application will just request enumerate the people on our local subnets and print their nick name, IP address and endpoint name to the console.  After creating a new C++ CLR console application in Visual Studio we need to add the Windows SDK path to our additional includes and our additional dependencies fields in our project. 

On my machine header files are here "C:\Program Files\Microsoft SDKs\Windows\v6.0\lib" and libs are here "C:\Program Files\Microsoft SDKs\Windows\v6.0\include". NOTE: these paths will be deferent on builds other then Windows Vista RC1 and are subject to where you installed the Windows SDK.

We also need to add three libraries: p2p.lib, p2pgraph.lib, Ws2_32.lib

The first two libraries contain all the peer to peer definitions and the last is WinSock2 and is needed when we convert an IP a