Thursday, 24 July 2008

DeepZoom Composer Tag "Generator" MkIII

A comment on a previous post says Because WebClient has a dependency on a web server running, the version I wrote won't be added as a project template into Deep Zoom Composer, which sounds like a shame and got me wondering how to get around the 'WebClient' problem.

The 'WebClient' problem is actually related to security and the sandbox. Kirupa's Tag Sample needs to load Metadata.xml into Silverlight/c#, and it uses WebClient to trigger an asynchronous download...

but you can't do that if you Silverlight control is hosted in a web page off your local disk!

It turned out to be pretty easy to get around - firstly here's a screenshot: the page has simply been double-clicked off the hard-drive, yet it is still able to load *some metadata* to enable tagging & description display.

Ah-ha - so you notice I said "some metadata" and not Metadata.xml. Since it is so hard to 'load' Xml off the filesystem (thanks to the Silverlight sandbox), and since my Tag Generator is parsing and re-writing Metadata.xml anyway, we just write another (JSON) file - Metadata.xml.js then go around the sandbox and load as JSON via Javascript Interop.

It took a little experimenting to get right, but the basic changes to make it work are:

1) Tag Generator emits JSON

2) Tag Generator saves "Metadata.xml.js"

3) Html page references "Metadata.xml.js"

4) Declare 'matching' C#/Silverlight class (to JSON), and a method to Deserialize to it

5) THE MAGIC Javascript Eval turns our string into JSON, replacing the LoadXMLData() at the start of the post

6) Update xmlClient_DownloadStringCompleted to walk the JSON object array instead of Xml, and the rest of the code 'just works'!

You'll want to add a couple of assembly references to your Silverlight (System.Json, System.ServiceModel.Web) and namespaces (System.IO, System.Text, System.Json, System.Runtime.Serializatin.Json) to get everything working. This post on Consum(ing) a JSON object in Silverlight set me on the right track, and the Silverlight and JavaScript Interop Basics filled in the gaps.

The Javascript Interop is capable of much more: HtmlPage.Window.Invoke for going to Javascript, and the [Scriptable*] attributes to expose managed code for Javascript to use; but a simple Eval was all I need for this little experiment.

p.s. I did wonder whether it's possible to "include" an .XML file in the HTML for DOM access... I vaguely remember IE supporting 'XML data islands' or something along those lines. However JSON definitely seems like the 'modern' way to approach the problem IMO, and without getting into x-browser compatibility stuff...


  1. Hi Craig. Your blog has been a great help! Thanks for that. I am trying to take the information from your post and from Kirupa's sample project to create some additional functionality, but I seem to have hit a hurdle.

    I have created several new XML fields (in the same way you created the 'description' field in your example). In addition to displaying the XML string data in text boxes, as shown in your example, I would like to show a large version of the image being moused over in a new image control. At first I thought it would be easy enough to link the "source" of the image control to a field in the XML for the file path similar to this:

    myImagePlaceholder.Source = imageMetadata[subImageIndex].ImagePath;

    This returns an error saying, "Cannot implicitly convert type 'string' to 'System.Windows.Media.ImageSource'

    It appears I need to use URI to resolve this error. Only problem is I am new to all of this and do not know how to hook that up. Any advice would be appreciated. Thanks!

  2. A quick google for "silverlight image source converter" turned up this post How to set image source on forums.

    Their answer is:
    imgMain.Source = new Uri(@"pictures/p3190014.jpg", UriKind.Relative);

    I've not tried it, hope it works.

    p.s. I assume ImagePath is a new attribute you've added to the metadata? DZ Composer includes a <Filename> tag but it is the image location on your local disk and won't work for your scenario (but I think you already knew that).

  3. Thanks Craig. Yes, ImagePath is a new attribute. I tried the URI code and recieved an error reading, "Cannot implicitly convert 'System.Uri" to "System.Windows.Media.ImageSource'".

    If only the image names listed in this XML file could populate the image control as easy as the text string data populates text boxes, this would be so simple.