Tuesday, March 11, 2008

Playing around with Silverlight 2.0 Beta 1

Since Silverlight Beta was released a few days, I wanted to have a look around and see what can you do with it.

After I did all the admins stuff like downloaded the beta, installed etc I started following ScottGu's tutorials on his blog to get an idea.

I thought, hell what I'm going to do! I've got no idea and certainly no skills as a designer, so I thought ok, lets simulate the AjaxAutoComplete extender and see where it takes us.

First of all I created a Silverlight application...

image

Then Visual Studio told me that in order to run a SL app, I need to host in a web page.

image

In project type above you can either choose, WebSite or WebAppliucation type..hrmm.

Upon clicking ok you are presented with an empty xaml page called Page.xaml

Now, the Silverlight control, because that is what we are creating, "lives" inside an html/aspx page. Note that the ctrl Source property is pointing to SuperApp.xap...

image

What the heck is this .xap file? I hear you ask..

Nothing too exciting, it is the compiled Silverlight application in zip format. This file contains the dlls it needs to run like System.Windows.Controls.dll and System.Windows.Controls.Extended.dll and the dll of your app in our case SuperApp.dll.

Dealing with the Xaml..

First of all I need to build the GUI for the TextBox and ultimately my dodgy AutoCompleteExtender.

What do we need?

  • Need a TexBox
  • Need some sort of DropDownList that is displayed as the user types in..
  • Need a button to submit the selected name eventually.

 

I choose <Canvas> as my layout, there is Grid and StackPanel. I used Grid too and it looked very easy to use, it was like creating an html table and then referencing to the x,y cells..very cool.

This is the Xaml for my text box. Note the Canvas.Top and Canvas.Left, no prize for guessing that it references the parent container of my textbox and it tells it to position it 100 pixels from the left and 20 from the top

<TextBox x:Name="TextBox_EmployeeName" Canvas.Left="100" Canvas.Top="20" Width="200" BorderBrush="CornflowerBlue" BorderThickness="1" Height="30" />

The button is very simple:

<Button Click="Save_Click" Content="Save" Canvas.Left="310" Canvas.Top="20" x:Name="Save"Width="60" >

I also added an event listener for the Click event.

Now for the ComboBox-look a like. There is no ComboBox in Silverlight Beta, so the closest thing is a ListBox.

Lets aligned right under the bottom of the TextBox and see what happens. At this stage of the game I was very hopeful that this will be able to be done.

<ListBox  KeyDown="EmployeeNames_KeyDown"  
        MouseLeftButtonDown="EmployeeNames_MouseLeftButtonDown"  
        Visibility="Collapsed" x:Name="EmployeeNames" 
        Width="200" Canvas.Left="100" Canvas.Top="46" />

Ok, so far so good, note I added two events to my ListBox, KeyDown and MouseLeftButtonDown. Basically these two events will 'listen' for when the user presses a key while this control has focus and also while the Mouse left button is pressed also while focus is on. ( I was thinking hrmm, this reminds me of SWING development back at uni in Java..)

Resulting page is: ( beautiful )

basic_Silver_Gui

Next question I had was. Ok I have to get some data from my Northwind database. I want text to resolve back to an EmployeeName. How am I going to do this? WebServices with WCF..

Note: This WebService has to be configured as BasicHttpBinding.

You cannot add a WebService to the Silverlight application, you have to do it somewhere else. In this case I added it you my WebSite. AddNewItem --> WCF Service.

I defined my [ServiceContract] Interface and my OperationContracts

and then my DataContract, because I wanted to return a MyEmployee object from my WCF webService.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    int CountEmployees();

    [OperationContract]
    MyEmployee GetEmployee(int id);

    [OperationContract]
    List<MyEmployee> GetAllEmployees();

    [OperationContract]
    String[] GetAjaxyEmployeeNames(String prefixText);
}

[DataContract]
public class MyEmployee
{   
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public int GetEmployeeID { get; set;}

    [DataMember]
    public String Address { get; set; }

    [DataMember]
    public String Title { get; set; }  
}

Then I had my MyService class that implemented my IService interface.

The function of interest is the GetAjaxyEmployeeNames, since it returns a String[] with the names that start with the prefixText passed on. Also note that you cannot add LinqToSql to Silverlight 2.0 Beta app, it is not supported at this stage, it does support LinqToXml though and one of ScottGu's tuts shows this. Since I added the Service to the WebSite, I just added a dbml file and drag-and-dropped the Employee table. Piece of cake.

public string[] GetAjaxyEmployeeNames(String prefixText)
{
       NorthwindDataContext ctx = new NorthwindDataContext();
       var emps = from e in ctx.Employees
                  where e.LastName.StartsWith(prefixText)
                  orderby e.LastName descending
                  select e.LastName + ", " + e.FirstName;
       return emps.ToArray<String>();        
}

Now we have the webService sorted out. We need to add a reference to our Silverlight app about this. The way to do it is very easy. Just right click on the project file Add Service Reference and you will be shown the dialog below..then discover and hopefully it will find the web service we just created.

image

Back to the Xaml now.

We have to add an Even listener to our TextBox, so when the text changes in the txtBox, the webservice will be called. This is easy, we just add a TextChanged event handler.

<TextBox TextChanged="TextBox_TextChanged"
        Canvas.Left="100" Canvas.Top="20" Width="200" Text=""
        x:Name="TextBox_EmployeeName"
        BorderBrush="CornflowerBlue" BorderThickness="1"
        Height="30">

I love the way VS does this for xaml pages, as soon as you type KeyDown the intellisense will ask you if you want to create a new listener, and if you press enter, VS will create a function in the codefile with some real cool naming by default.. wish we had this for normal asp.net! ( ScottGu said this is coming soon!)

I also added a KeyDown handler, so when the textbox has focus and the user presses the down arrow key, the behaviour of the real AutoCompleteExtender is simulated and the focus and control moves on to the ListBox.

event_intellegince

We have the handlers now, next we have to create a proxy to our WebService so they methods it exposes can be called. 

  1. Add two using statements to System.ServiceModel and System.ServiceModel.Channels.
  2. Create a binding element in the scope of the class ( so we can use it everywhere!). Binding binding = new BasicHttpBinding(); Bindings specify the details for a client to communicate with the Service. The only binding supported at this stage is BasicHttpBinding.
  3. Next we have to create an EndPointAddress. This gives the address of the Service to be called upon. So we just use the address where this service is being hosted.
  4. EndpointAddress address = new EndpointAddress("http://localhost:50740/SilverlightApplicationFirstEver_Web/Services/MyService.svc")
     

We now have everything we need to create our proxy and call the Service. Remember we have a listener for when the user enters text in our TextBox and so the TextChanged event fires.

To create the proxy to our service, the proxy's constructor takes in the binding and endpointAddress.

To now call the methods in our service we have to realise that all calls in Silverlight are asynchronous. In this case I'm using the event driven pattern where the proxy contains two members for each potential call to the Service, these are an async method and a completed event that is raised once the async call returns. This results on the following members:

resultingmethods 

The complete function looks like this:

completed_function

And the proxy_AjaxyEmployeeCompleted function that handles the returned data from the WebService is:

proxy_completed_call 

Note that the ListBox is hidden unless there is a result to display.

Now as soon as you type something in, the service will be displayed and the ListBox ItemsSource property ( think of it as a DataSource in Asp.net ) is bound to args.Result, which is a String[]

extenderinaction 
 

Thats basically it, I have more functions to simulate the real AutoCompleteExtender, like for example when the user clicks with the mouse on say "King, Robert" that Employee name will be selected and will be copied into the TextBox.

Also I have a listener on the ListBox that listens for any down arrow key pressed and mouse left button events that copy the SelectedItem text to the TextBox again.

mousedown

And to finish up, when the TextBox has focus and the user presses the down arrow key, this means that she will like to go on an navigate through the employee names in the ListBox. To to this we added a KeyDown listener on the TextBox.

keydowned_textarea 
 

Out of interest I then opened the solution file in Expression Blend 2.5 March edition and got to play with colours etc etc. Very cool but well outside my domain all this designer stuff..

image 

Well, is all good, I learned heaps about Xaml etc. VEry powerful, but also learned that things can get very complicated very quickly. There are some sample apps that come with Blend that are plain scary.

image 

A photo book where you can "grab" the pages from the lower right corner..

image 

impressive this paint look-alike..

image 
 
 
 
 
 

 

     

3 comments:

David Tchepak said...

Another great post El#! What's the deal? I finally talk you into blogging after 2 years of trying and then you go and immediately show me up!

Keep up the good work :-)

Unknown said...

Thanks for the encouragment, it is appreciated!!
:-)
And nop, im not showing you up at all, your articles are very in depth. mine is click here and there .. lol

CML said...

Good!

I want to write my own later.