.NET Blog

Tony Cavaliere

 
My Favourite Albums
  And the Grappa wins.
E-mail me Send mail
Add to Technorati Favorites AddThis Feed Button

Subscribe to Cynot Why Not


Recent posts

Disclaimer

Hey unlike other bloggers I stand by what I say but just in case. The opinions expressed herein are my own except on Tuesday when the second card is not turned up otherwise it ain't worth squat.

© Copyright 2010

Headless Silverlight Application

A headless Silverlight application is a Silverlight application that contains no user interface. The obvious question is why, why on earth would you ever want to create a web site with a Silverlight control that has no UI? I can think of good reason. What if you want to make a cross domain call. Traditionally, this was done by making a call back to the same domain server. The server would make the requested call on behalf of the client and return the data back to the client. Wouldn't it be great if the client could make the call directly.

Silverlight has the capability of making cross domain calls provided the server that hosts the service has been given access via the either the ClientAccessPolicy.xml or crossdomain.xml file. This post will describe how to use a headless Silverlight control to simplify cross domain calls from the client browser. I will not spend too much time discussing how to create a WCF service but rather will use an existing WCF service. The reader is directed to a previous post Calling a WCF Service from Silverlight 2.0: part Two. Likewise, I will not be discussing, in any great detail, how interoperability between Silverlight and the HTML DOM is done. Again the reader is encouraged to read a prior post  How to communicate between Silverlight controls.

Let's start writing this headless Silverlight application.

Using VS2008, create a new Silverlight application. I decided to call the project HeadlessSilverlight. I like to use jQuery and if you want to follow this tutorial, as is, then I recommend you add jQuery.js to the web project. You can download jQuery from jquery.com. I also like to remove the generated default.apsx file and rename the generated TestPages to default. So the HeadlessSilverlightTestPage.aspx is renamed to default.apsx and the HeadlessSilverlightTestPage.html to default.html. After doing all this you should have a solution similar to Figure 1.

Figure 1: Initial Solution

Solution1

The next step to is alter the Silverlight control so that it has no height or width. Edit the default.aspx and make the following changes:

  1. Remove the width and height in the Silverlight control.
  2. Remove the style attribute from the div element that hosts the Silverlight control.

Listing 1 contains the altered markup.

Listing 1: The Silverlight control with no height or width.

   41         <div>

   42             <asp:Silverlight

   43               ID="Xaml1" runat="server"

   44               Source="~/ClientBin/HeadlessSilverlight.xap"

   45               MinimumVersion="2.0.31005.0" />

   46         </div>

Similarly the XAML needs to be modified. The modifications are shown in Listing 2.

Listing 2: headless Silverlight XAML markup.

    1 <UserControl x:Class="HeadlessSilverlight.Page"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4    >

    5     <Grid x:Name="LayoutRoot"></Grid>

    6 </UserControl>

Of note both the grid and the user control have no width or height.

We need some way to initiate the cross domain service call. Modify the default.apsx markup to include a button. When the user clicks this button we will call the service but rather than use javascript to directly call the service we will use Silverlight to accomplish the task. Listing 3 contains the markup for the button. Place this after the markup for the Silverlight control.

Listing 3: HTML Button  

   47         <div>

   48           <input

   49             id="btnCrossDomain" type="button"

   50             value="Call Cross Domain Service" />

   51         </div>

Notice that we have not wired up the click event in markup and this is where jQuery shines. jQuery makes it easy to decouple the UI from behaviour. Enough said let's see how the click is wired up.

Listing 4 contains the javascript call to jQuery that wires up the click event to an anonymous function (sometimes called inline function).

Listing 4: Supporting javascript code.

   20     <script type="text/javascript" src="jquery.js"></script>

   21 

   22     <script type="text/javascript">

   23       // Use jQuery to attach a function to the button click event

   24       $(function() {

   25         $('#btnCrossDomain')[0].onclick = function(event) {

   26           //call service via silverlight

   27           var host = document.getElementById("Xaml1");

   28           host.content.SL_Headless.CallService();

   29         }

   30       });

   31       // The Silverlight managed code will call this javascript function

   32       // when it has made the service call.

   33       function displayResponse(response) {

   34         alert(response);

   35       }

   36     </script>

First we need to include the jQuery library. This is done at line 20. Lines 24 to 30 is basically how we wire up the click event of the button with id #btnCrossDomain with an anonymous function. This anonymous function makes the call into the Silverlight managed environment and ultimately makes the service call. More on that later. The function displayResponse will be called from the Silverlight managed environment and will display the data from the service call. More on that later.

Let's examine more closely how the call to Silverlight is made. Line 27 is used to retrieve the Silverlight plug-in instance. This instance exposes a content property  from which you can access a scriptable object. Only managed instances that have been explicitly registered are accessible from javascript. Once we have a reference to the scriptable object then any method that has been decorated with the ScriptableMemberAttribute can be called. This can be a little confusing and will become clearer when we investigate the Silverlight code.

But before we can add the code that actually calls the WCF service, we need to add a service reference to the Silverlight project. Select the Silverlight project and press the right mouse button and select the Add Service Reference menu option. This will bring up the Add Service reference dialog. I have decided to use a service I created for an earlier post. You are free to use this service or any other but remember if you chose a third party service then make sure that they have granted access to the service via the ClientAccessPolicy.xml file. Type the following in the Address field of the dialog http://www.cynotwhynot.com/services/people/PersonService.svc  and then select Go. After a bit of time the Services listbox should contain a service named PersonService. Lastly, change the namespace to PersonProxy. Figure 2 shows this dialog.

Figure 2: Adding a reference to the WCF service.

Add Service  

Selecting the OK button will add the proxy to the Silverlight project. This service contains a single method, GetPeopleAsync and is used to get a list of Person objects.

With this reference in place we can concentrate on the code behind for the headless Silverlight control. Listing 5 contains the code for Page.xaml.vb

Listing 5: The Page.xaml.vb code behind.

    1 

    2 Imports System.Windows.Browser

    3 Imports System.Collections.ObjectModel

    4 

    5 Partial Public Class Page

    6     Inherits UserControl

    7 

    8     Public Sub New()

    9         InitializeComponent()

   10     End Sub

   11 

   12     <ScriptableMember()> _

   13     Public Sub CallService()

   14         Dim proxy As New PersonProxy.PersonServiceClient()

   15         AddHandler proxy.GetPeopleCompleted, AddressOf onGetPeopleCompleted

   16         proxy.GetPeopleAsync()

   17     End Sub

   18 

   19     Public Sub onGetPeopleCompleted( _

   20         ByVal sender As Object, _

   21         ByVal e As PersonProxy.GetPeopleCompletedEventArgs)

   22 

   23         Dim response As String

   24         If e.Error Is Nothing Then

   25             response = String.Format( _

   26                 "Cool a cross domain call. {0} {1}", _

   27                 e.Result(0).First, e.Result(0).Last)

   28         Else

   29             response = String.Format( _

   30                 "Cool a cross domain call but an error occurred. {0}", _

   31                 e.Error.ToString)

   32         End If

   33 

   34         'Call Javascript to display the response

   35         Dim displayResponse As ScriptObject = CType(HtmlPage.Window.GetProperty("displayResponse"), ScriptObject)

   36         displayResponse.InvokeSelf(response)

   37 

   38     End Sub

   39 

   40 

   41     Private Sub Page_Loaded( _

   42         ByVal sender As Object, _

   43         ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

   44         HtmlPage.RegisterScriptableObject("SL_Headless", Me)

   45     End Sub

   46 

   47 End Class

Lines 12 through 17 contains the code that makes the call to the WCF service. The ScriptableMemberAttribute on line 12  and the call to RegisterScriptableObject on line 44 exposes the CallService method to javascript.  The call to the WCF service is made within the CallService method. The Silverlight model enforces that all out of band calls must be made asynchronously and therefore the response must be processed within a callback, OnGetPeopleCompleted. This callback takes the return data (e.Results) and packages it into a string. For simplicity only the first person in the list is included in the response string. If a problem occurs when calling the service, the error is placed in the response string. Finally, lines 35 and 36 call the javascript function, displayResponse and if you recall this function calls alert, displaying the response string .

Figure 3 shows the alert containing the data from the WCF service call. Notice that the alert contains the person John Smith. That's it a cross domain call from within the client browser.

Figure 3: The headless Silverlight application running in a browser.

headless app running 

Without your space helmet, Dave, you're going to find that rather difficult.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight
Posted by CynotWhyNot on Friday, November 28, 2008 4:55 PM
Permalink | Comments (21) | Post RSSRSS comment feed

Jazz up your photo album with Photosynth

I was reading my typical list of blogs and came across a posting describing this unique way of displaying your photos. Photosynth examines photos for similarities and then reconstructs the scene. For example, you can take a panoramic set of photos and then feed the photos to Photsynth and it will stitch the photos together creating what they call a synth.

Photosynth not only will stitch the photos but also provides 20 GB of storage and will create the necessary HTML so you can add the composite to your web site.

I only spent a few minutes and was able to create the following. Check out Photosynth for more impressive synths.You may need to install a plugin.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by CynotWhyNot on Saturday, November 22, 2008 2:40 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Silverlight: Finding the default style

One of the things I like about Silverlight is the ability to customize existing controls. Just about every control that ships with Silverlight has a default style. You are free to override the default style, create a new style from scratch or if you so choose edit a copy of the default style. Using the new style is as simple as setting the Style attribute  Style="{StaticResource StyleName} where StyleName is the name of the style. For further information on styling refer to the following post.

But where can you find the default style for a control?

Excluding third party tools, I know of at least three ways;

1. From the Silverlight Documentation

If you haven't done so then download the offline Silverlight documentation. The default styles for the Silverlight controls are published in this document.

SL Doco Button Style

2. Use Blend

The second way is to use blend. All you need to do is select the control and right click and choose Edit Control Parts (Template)->Edit Copy. This will create a copy of the default style and attach it the control.

blend button style

3. .NET Reflector (Before you begin I realize this is a third party tool, but it's my blog and I use it so much it doesn't feel like one anymore)

The final method is to use everybody's friend, .NET Reflector. Find the assembly for the control. For example, if you are wanting the default style for say a button then add the following assembly to .NET reflector.

C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Reference Assemblies\System.Windows.dll

Next navigate to the Systems.Windows->Resource->System.Windows.g.resources node and double click it. After doing so you .NET Reflector will appear similar to the the following

NET reflector style

Next double click the XAML file in the disassembler pane. Provider you have associated the XAML file extension with the VS2008 executable you should see the default styles for all the controls in that assembly, similar to the figure below. Note the default file association for XAML is IE which does not render the XAML correctly.

VS2008 XAML

Which method do I prefer? The first will only work with the documentation and the code are in sync. Both Blend and Reflector will produce styles that are in sync with the code, however, Blend is not free and not every developer will have a copy. Need I say more.

Guess the movie

Seventeen *days?* Hey man, I don't wanna rain on your parade, but we're not gonna last seventeen *hours!* Those things are gonna come in here just like they did before. And they're gonna come in here...

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight
Posted by CynotWhyNot on Saturday, November 15, 2008 5:57 PM
Permalink | Comments (29) | Post RSSRSS comment feed

reCAPTCHA what a brilliant idea!

Most of us have seen them, CAPTCHAs (Completely Automated Public Turing test to tell Computers and Humans Apart). Those weird looking characters that we need to re-type in order to gain access to some web site or resource. Well, they serve a purpose and that is to make sure the user is a real live person rather than some computer script trying to hack a site by perhaps trying to flood the server with large numbers of requests.

I just found out about a brilliant service called reCAPTCHA. It is totally free and with a few lines of code you can add this security feature. But what makes it brilliant is that the service is also digitizing books while it is being used. That's right each time a person types in the characters of the CAPTCHA scanned text from a book is being digitized.

reCAPTCHA

How does that work you may ask?

From the reCAPTCHA site

But if a computer can't read such a CAPTCHA, how does the system know the correct answer to the puzzle? Here's how: Each new word that cannot be read correctly by OCR is given to a user in conjunction with another word for which the answer is already known. The user is then asked to read both words. If they solve the one for which the answer is known, the system assumes their answer is correct for the new one. The system then gives the new image to a number of other people to determine, with higher confidence, whether the original answer was correct.

If you working on a site and require CAPTCHA then please check this service out. It's free and better yet your users will be helping out, digitizing books.

Guess the movie 

Come on... Come on! Do it! Do it! Come on. Come on! Kill me! I'm here! Kill me! I'm here! Kill me! Come on! Kill me! I'm here! Come on! Do it now! Kill me!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | HTML
Posted by CynotWhyNot on Thursday, November 13, 2008 2:49 PM
Permalink | Comments (8) | Post RSSRSS comment feed

How to communicate between Silverlight controls

A while back I discovered a great post about how to establish communication between Silverlight controls on the same page. I had already known how it could be accomplished using Javascript and an example of this approach is used by my Silverlight Gallery. But this other way caught my attention and I have decided to post about it. Jeff Prosise's Blog contains a series of posts called  Cool Silverlight Tricks. Currently there are only 5 tricks, but, they are all great. Make sure you check them out. I will not be discussing the Javascript approach in the blog post. The reader is referred to this post

Jeff basically replaces all the Javascript that would normally be used to establish communication with equivalent Silverlight HTMLBridge calls. Now why didn't I think of that! Let's take a look at some code.

We start by creating a Silverlight project. This project will require two Silverlight controls. I have decide to call the controls SourceSilverlight and TargetSilverlight. The SourceSilverlight control, as it name implies, will be the control that will send commands to the TargetSilverlight. I liked the visual aspect to Jeff's example so I used it here. Both controls will have a circle positioned identically on their respective canvases. When the user moves the circle in the SourceSilverlight control it sends the new postion to the TargetSilverlight control causing the circle to move identically.

Listing 1 contains the code behind for the SourceSilverlight UserControl. I have excluded the XAML markup as it is extremely simple containing an ellipse with a name of ball. The MouseMove, MouseLeftButtonDown and MouseLeftButtonUp events are all wired up and are used to enable dragging.

Listing 1: SourceSilverlight UserControl Code Behind

    1 

    2 Imports System.Windows.Browser

    3 

    4 Partial Public Class Page

    5     Inherits UserControl

    6 

    7     Public Sub New()

    8         InitializeComponent()

    9     End Sub

   10 

   11 #Region "Move Ball Events"

   12     Private isMouseDown As Boolean = False

   13     Private Sub ball_MouseLeftButtonUp( _

   14         ByVal sender As System.Object, _

   15         ByVal e As System.Windows.Input.MouseButtonEventArgs)

   16         isMouseDown = False

   17         CType(sender, Ellipse).ReleaseMouseCapture()

   18     End Sub

   19 

   20     Private Sub ball_MouseLeftButtonDown( _

   21         ByVal sender As System.Object, _

   22         ByVal e As System.Windows.Input.MouseButtonEventArgs)

   23         isMouseDown = True

   24         CType(sender, Ellipse).CaptureMouse()

   25     End Sub

   26 

   27     Private Sub ball_MouseMove( _

   28         ByVal sender As System.Object, _

   29         ByVal e As System.Windows.Input.MouseEventArgs)

   30         If isMouseDown Then

   31             Dim ball As Ellipse = CType(sender, Ellipse)

   32             Dim cx As Double = e.GetPosition(LayoutRoot).X

   33             Dim cy As Double = e.GetPosition(LayoutRoot).Y

   34             ball.SetValue(Canvas.LeftProperty, cx - ((ball.Width) / 2))

   35             ball.SetValue(Canvas.TopProperty, cy - ((ball.Height) / 2))

   36             MoveTargetBall(cx - ((ball.Width) / 2), cy - ((ball.Height) / 2))

   37         End If

   38     End Sub

   39 #End Region

   40 

   41 #Region "Communication to Target Silverlight"

   42     'This is the Jeff Proise's cool silverlight trick. No need for javacript.

   43     'Just call HTML bridge functionality duplicating what you would have done

   44     'in javascript.

   45     Private _target As ScriptObject = Nothing

   46     Public ReadOnly Property Target() As ScriptObject

   47         Get

   48             If _target Is Nothing Then

   49                 'I have hardcoded the id of the target silverlight control.

   50                 'A better solution would be to use the InitParameters feature.

   51                 Dim slhost As HtmlElement = HtmlPage.Document.GetElementById("Xaml2")

   52                 Dim content As ScriptObject = CType(slhost.GetProperty("content"), ScriptObject)

   53                 _target = CType(content.GetProperty("SLScriptObject_TargetSilverlight"), ScriptObject)

   54             End If

   55             Return _target

   56         End Get

   57     End Property

   58 

   59     Private Sub MoveTargetBall(ByVal x As Double, ByVal y As Double)

   60         Target.Invoke("MoveBall", x, y)

   61     End Sub

   62 #End Region

   63 

   64 End Class

I have divided the code into two regions. The first region deals with mouse events and is responsible for moving the circle. Note that at the end of the ball_MouseMove method we call method MoveTargetBall passing as parameters the new position of the circle. I will not discuss how this region of code works as it is a standard drag implementation and is not relevant to the topic at hand. The second region of code deals directly with the communication between the SourceSilverlight and TargetSilverlight control.

Let's examine this code. The real work is done in the ReadOnly Target Property. In this property, we first obtain a reference to the TargetSilverllght control. This is accomplished by calling the GetElementById method passing to it the ID of the TargetSilverlight control. For the purposes of this post I have hard coded this ID, however, a better approach would be to make use the InitParameters. Next using this reference, we call the GetProperty method passing the string content. This returns a reference to a ScriptObject, a representation of a DOM object, and in this case it references the TargetSilverlight control. Finally, using this ScriptObject reference, we make a call to GetProperty this time passing the string  SLScriptObject_TargetSilverlight. What does this string represent you may be asking? Great question, basically, this is the token that was used when the TargetSilverlight control registered a scriptable object.  This will become clearer when we look at the code behind for the TargetSilverlight control.

So all that is required to invoke a registered method from the TargetSilverlight Control is to called the Invoke method passing the string representation of the method and the X and Y position of the circle.

A note of caution. While this approach eliminates any need for Javascript, it comes at a price. This method requires 4 round trips between Silverlight and the browser (lines 51, 52, 53 and 60), whereas, a Javascript approach requires only one round trip.

Listing 2 contains the code behind for the TargetSilverlight control.

List 2: TargetSilverlight Control Code Behind

    1 

    2 Imports System.Windows.Browser

    3 

    4 Partial Public Class Page

    5     Inherits UserControl

    6 

    7     Public Sub New()

    8         InitializeComponent()

    9     End Sub

   10 

   11     <ScriptableMember()> _

   12     Public Sub MoveBall(ByVal x As Double, ByVal y As Double)

   13         ball.SetValue(Canvas.LeftProperty, x)

   14         ball.SetValue(Canvas.TopProperty, y)

   15     End Sub

   16 

   17     Private Sub Page_Loaded( _

   18         ByVal sender As Object, _

   19         ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

   20         HtmlPage.RegisterScriptableObject("SLScriptObject_TargetSilverlight", Me)

   21     End Sub

   22 End Class

Take a look at the MoveBall method, this the method that the SourceSilverlight control called to communicate the new position of the circle (line 60 in listing 1).  Note the use of the ScriptableMemberAttribute. Basically, this makes the method accessible to Javascript callers or in our case via the HTML bridge from another Silverlight control. The Page_Load method calls the RegisterScriptableObject method passing to it the token SLScriptObject_TargetSilverlight and this is the typical pattern for exposing a Silverlight method to a Javascript caller.

The last listing, Listing 3, contains the page markup used to host these two Silverlight controls. Nothing out the ordinary.

Listing 3: Markup used to host the Silverlight controls.

   12 <body style="height:100%;margin:0;">

   13     <form id="form1" runat="server" style="height:100%;">

   14         <asp:ScriptManager ID="ScriptManager1" runat="server">

   15         </asp:ScriptManager>

   16         <div style="float: left; padding-right: 10px; padding-left: 10px; padding-top: 10px;">

   17             <asp:Silverlight

   18               ID="Xaml1"

   19               runat="server"

   20               Source="~/ClientBin/SourceSilverlight.xap"

   21               MinimumVersion="2.0.31005.0" Width="300px" Height="300px" />

   22         </div>

   23         <div style="padding-top: 10px;">

   24             <asp:Silverlight

   25               ID="Xaml2"

   26               runat="server"

   27               Source="~/ClientBin/TargetSilverlight.xap"

   28               MinimumVersion="2.0.31005.0" Width="300px" Height="300px" />

   29         </div>

   30     </form>

   31 </body>

If you would like to see this in action please navigate to this site. 

Guess the movie

Go ahead, Zeus. Throw down a thunderbolt, let the earth swallow me up. I defy you!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight
Posted by CynotWhyNot on Tuesday, November 11, 2008 4:54 PM
Permalink | Comments (18) | Post RSSRSS comment feed