Felix and I have been presenting around Europe at the Remix Essentials events giving away a white labelled Silverlight mashup. Being on the Silverlight TAP I have been trying to keep the project up to date with the latest drops but fell behind. So while in Mexico on the Friday evening I thought that I would try and do a simple upgrade to Beta 2.
So for those of you out there that have not seen the presentation I have put the complete deck up on my public SkyDrive area so you can take a look at the deck. However, I will give you a little more background about the application. Felix and myself wanted to build a simple Silverlight mashup so that we could gain a better understanding of Beta 1 and how we could bend it. My other goals were to try out a simple testable pattern based on an MVP approach; and make the entire app a white labelled application so that people who have not done Silverlight before can easily change the endpoints and change the skin of the application so that they could get up to speed quickly with Silverlight. The idea was that this would be attractive to developers and designers so that it would act as a stepping stone to try out the technology and the workflow required to build an application.
So lets open the Beta 1 solution and see what happens. Visual Studio works out that my copy is using the older Beta 1 version and politely asks me if I wish to upgrade the solution to Beta 2. The solution loads up with all the correct bindings in place so I hit F5 and watch the output window for errors.
The only compilation issue was about the multi scale image control. Checking the documentation you will find a section on breaking changes for Deep Zoom and the multi scale image control.
and
After making these changes build the app. Green light cool.
Next its time to change the Deep Zoom Compositions which I created for Denmark and Austria, forgot my camera in Dublin and Mexico :-(
So open up the old files and simply make sure that the composition option and output as files options as selected, then hit the export. Once this was done copy over the goo and drop them into the ClientBin. To get a definitive list of new stuff check out the Expression team blog. Once that's done the final part is to update the code.
Beta 1
case Model.RemixEvents.Denmark:
{
this.DeepZoom.Source = new Uri(this.remixDenmarkSource);
break;
}
Beta 2
case Model.RemixEvents.Denmark:
{
this.DeepZoom.Source =
new DeepZoomImageTileSource(new System.Uri(this.remixDenmarkSource));
break;
}
So far so good, no real pain to be had.
The mashup contains a simple User Control to wrap up all the functionality of a deep zoom view and the corresponding View Model that contains all the logic for the view, such as filtering of images and working out which image in the collection has been selected. Curious of the new Deep Zoom Composer and wanting to interact with the new UI and its features, I decided to create a dummy project and see what happens. I find that with new technology it best to start real simple and then layer on the complexity so I created a new simple project with 2 images and left all the defaults in place. View the collection using the in browser option and the collection appeared ready for action. Cool...
Then select the open in Blend option ready to create the filtering GUI to test out the filter as this code needs to change to come inline with the new metadata.xml file that the DZC auto gens for us.
Unfortunately, I was getting an error as the project file which opens is incorrect.
If you use the default values you will get something like DeepZoomOutput.sln that DZC has asked it to open. However, it should be DeepZoomProject.sln. Not a biggie but a little frustrating when you want the process to be a seamless one. Ok I thought open everything up in VS08 just in case there is a problem with the new version and VS will usually give you better debug information at Runtime. So I open the project with no errors and hit F5. I get a Xaml error in the browser.
My next stop is to right click on the html file and select the view in browser option, the Browser starts up and loads up my Silverlight goo with no errors. On closer inspection the clue is in the URL which is given to the browser hitting F5 it was :-
C:\Projects\ConchangoLabs\DeepZoomFilter\FitlerExample\Collection\ascollection\DeepZoomProject\Bin\Debug\TestPage.html
However if you right click and say view in browser it references the webdev server instance :-
http://localhost:56724/DeepZoomProjectWeb/ClientBin/DeepZoomProjectTestPage.html
The way around this is to make the web site your startup app and make the .html page your start page and say yes to debugging support for Silverlight and all is well again.
The video plays and the Deep Zoom Collections are loaded into the User Control and my interactions still work. However I am still not getting any data. Strange after checking all my bindings and everything is looking good. So debugging the page around the where I bind up my data and find that Silverlight is barfin' with an UnauthorizedAccessException, due to cross-threaded access. The threading model in Beta 2 has changed, and the Invalid cross-threading exception is due to the code trying to update the UI while still on the background thread. So we need to marshal back on to the UI thread and update the control with the new data from the response stream. After a bit more digging I found a couple of recent posts by Scorbs on WebClient and HttpWebRequest changes in Beta 2 here. So my next job is to change the way in which I update the UI from within the ModelView for that View. The original code looked like this.
In WPF we have something called the Dispatcher, which allows us to do a BeginInvoke and add the UI work we want to do into the queue for the UI thread to process depending on the priority that we sent, if you are not familiar then Dr WPF has a good article or check out msdn. However, the Silverlight Beta threading model is not the same and the call to the Dispatcher's Begin Invoke takes only a delegate, so you can't set the priority of the work put into the queue. But doing the BeginInvoke is only part of the story and you don't actually need to do it in this particular case, what is important is to use the SynchronizationContext and call its Post method which takes a delegate and an Object. Cool however, there is a little gotcha we need to look out for. Although you can call the Current property on the SynchronizationContext it is not guaranteed to return you the context of the UI thread, so SynchronizationContext.Current.Post(delegate, object) is not going to do the job. To get around this you need to grab the Context in the constructor of the main page. For example my start page looks like this.

Page.xaml.cs and in the constructor I am getting hold of the context and passing this into the constructor of my ViewModel, the ViewModel then will retain this reference so that all my other calls to add items to the UI queue will use this reference. It ends up looking like this.

The last bit of work to be done is to add the call to the BeginIvoke on the Dispatcher to update the UI now that we have a hold on the UI thread. Notice that as we are on the background thread it feels right to process all the data sent here rather than doing this work on the UI and blocking something that could be reducing the experience which the user is having.
That was quite a lot to get through so you may want to go and grok this code a little before you crank your own, however before you do read on.
Everything is building so I fire my app and sit back to wait and see my data in the control.... However nothing gets displayed. Strange... Well not really as there have been schema changes in Beta 2 the styles associated with my control nolonger work. So its time to jump into the Xaml and remove the associated styles from the ListBox. Build and run.... Whoa I see data in the ListBox.
After changing each of the ViewModel's to use the same pattern as above it's time to start changing the controls styles which I will attempt in the next post about upgrading from Silverlight Beta 1 to 2.
If you have come across any other gotcha's then I would like to hear about them.