Fun with DeepZoom

I've been experimenting a little bit with DeepZoom, a new extension for Silverlight, currently in beta from microsoft. This works together with the MultiScaleImage control from silverlight, giving you a very performant and smooth picture browsing experience.

It does this by dividing a large image into 256x256 squares and building a pyramid of smaller sized images, again divided into 256x256 squares, up until it reaches a single pixel image. This adds 33% of extra space required on disk, which I believe isn't very much.

This way it can load the squares it needs at the right zoom level, reducing the amount of pixels downloaded (at the same time).

To try this yourself, you first need the the Deep Zoom Composer utility:

http://blogs.msdn.com/expression/archive/2008/03/05/download-the-preview-of-the-deep-zoom-composer.aspx

Start it up and create a new project:

DZ_CreateProj

On the Import tab click the "Add Image..." button and import any picture you want:

DZ_Ïmport

Next click on the Compose tab and position your pictures the way you want:

DZ_Compose

And as the last step export your stuff (first choose a name for your export):

DZ_Export

This will create a directory structure:

Heroes

With Visual Studio 2008, create a new Silverlight project with default settings (with extra web project). Build the project, then copy the above contents into the web project's ClientBin folder (you need to build the project before you will see this folder).

Then in page.xaml first remove the Width and Height properties, then add a MultiScaleImage control with source property pointing to the info.bin file:

 

<UserControl x:Class="DeepZoomDemo.Page"     xmlns="http://schemas.microsoft.com/client/2007"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >     <Grid x:Name="LayoutRoot" Background="White">      <MultiScaleImage Source="info.bin" />    </Grid> </UserControl> 

Build your project and run. That's it!

Next entry will show how to add Zoom and move support to this solution.

Silverlight 2.0 DataBinding Explained (a bit) :)

 

Silverlight supports data binding, but currently there is a lack of samples explaining some of the nicer concepts, plus some of the things are not as you might expect.

Data binding in Silverlight is through the {Binding <Path>} syntax, for example to bind a TextBox's Text property to the Value property of some class you would use

<TextBox Text="{Binding Value}"  />

The catch is that this is a one way binding, if you change the Text in the TextBox the Age property doesn't get updated...

The solution is simple, you need to set the Mode property of the Binding object to TwoWay like this:

<TextBox Text="{Binding Value, Mode=TwoWay}"  />

Now modifying the Text property will modify the Value property (and vice versa).

Next on my agenda is data conversion. You can do this by using a class that implement the IValueConverter interface, for example:

public class DoubleToBrushConverter  : IValueConverter {   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)   {     string v = (value ?? "0").ToString();     double cutoff = parameter == null ? 30 : double.Parse( parameter.ToString() );      if (double.Parse(v) < cutoff)       return new SolidColorBrush(Colors.Green);     else       return new SolidColorBrush(Colors.Red);   }    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)   {     throw new NotImplementedException();   } } 

This class will convert the value to a brush, nice if you want to show the user that an invalid or unusual value was entered. You can use this as follows:

<TextBox Text="{Binding Value, Mode=TwoWay}"           Background="{Binding Value,                                Converter={StaticResource converter},                               ConverterParameter=40}" /> 

The ConverterParameter will get passed into the Convert method as the parameter parameter.

Please note that we don't need to implement the ConvertBack method of the IValueConverter interface because the user will not be able to change the background color.

image

When the value goes above 40 the background turns red.

Last thing is the Source property of the Binding element. With this you can point to some object on your Page, stored as a resource:

<TextBox Text="{Binding Value, 
                  Mode=TwoWay, 
                  Source={StaticResource someObject}}"  />

 

This of course opens up using Element binding, which means binding to elements of your page to each other. The technique I propose is using some temporary object and binding the controls to this object.

For example, to bind three controls (two textboxes and one slider) to each other use following markup:

<TextBox Text="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}"  /> <TextBox Text="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}"           Background="{Binding Value,                               Source={StaticResource someObject},                               Converter={StaticResource converter},                                ConverterParameter=40}" />  <Slider x:Name="theSlider"   Minimum="0" Maximum="100" SmallChange="1" LargeChange="10"     Value="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}" /> 

Each binding refers to the same Source, which I've declared on top of the page resources:

<UserControl.Resources>   <u:DoubleToBrushConverter x:Key="converter" />   <u:ElementBinding x:Key="someObject" Value="66" /> </UserControl.Resources> 

The DoubleToBrushConverter class is the one on top, the ElementBinding class looks like this:

public class ElementBinding : INotifyPropertyChanged {   double val;    public double Value   {     get { return val; }     set { val = value; OnPropertyChanged("Value"); }   }    public event PropertyChangedEventHandler PropertyChanged;    protected virtual void OnPropertyChanged(string propName)   {     if (PropertyChanged != null)       PropertyChanged(this, new PropertyChangedEventArgs(propName));   } } 

The class implements the standard INotifyPropertyChanged interface to support databinding.

A demo project containing this sample can be found here.

First look at Silverlight 2 - ScottGu Tutorial

Well, I've just completed the full tutorial from Scott Gu, and I must say it was a pleasure to do. I already have a lot of experience with WPF, XAML and Silverlight, so it was a big eye-opener into Silverlight's new features. For those of you who've attended my WPF training I told you Silverlight would have databinding and styles/templating, and I must say it really fulfills it promise. At the end the lab even makes you use your Silverlight controls in an WPF application. Cool!

Using BackgroundWorker with Silverlight 2.0

 

A long time ago I wrote two articles on the asynchronous processing model in .NET 1.0 and .NET 2.0. This last part was mainly about the BackgroundWorker class for running things in the background.

This same model also works in Silverlight 2.0 (Beta 1). So if you need to do some heavy calculation or anything else taking a long time you should use the BackgroundWorker class.

Using the BackgroundWorker is easy, first create an instance of it:

BackgroundWorker worker = new BackgroundWorker();

Then set the DoWork event to do the "long" thing, for example here emulated with a simple sleepy loop:

worker.DoWork += 
  delegate(object sender, DoWorkEventArgs e)   {     DateTime start = DateTime.Now;     for (int i = 0; i < 100; i++)     {       Thread.Sleep(50);       worker.ReportProgress(i);     }      e.Result =        string.Format("Done, this took {0} sec",        DateTime.Now.Subtract(start).TotalSeconds);   };

This worker reports on progress using the ReportProgress method. We need to do this because in the DoWork event it is forbidden to touch any of the controls. It is allowed on the ProgressChanged event:

worker.WorkerReportsProgress = true; worker.ProgressChanged += 
  delegate (object sender, ProgressChangedEventArgs e)   {     timer.Text = string.Format("{0}% done", e.ProgressPercentage);     progress.Value = e.ProgressPercentage;   } 

Also note that the last line of the DoWork event sets e.Result. This is used to pass the result to the event which handles the completion of the work, the RunWorkerCompleted event:

worker.RunWorkerCompleted +=    delegate (object sender, RunWorkerCompletedEventArgs e)   {     timer.Text = (string)e.Result;   }; 

 

Again you're not allowed to change controls in the DoWork event, so if you want to update controls when the calculation is done, you do this in the RunWorkerCompleted event.

The BackgroundWorker also supports canceling the long running task, and handling error in the correct way. More in above mentioned articles.

A complete sample project about using the backgroundworker can be found here.

 

WCF Service in Visual Studio "locking up" for a minute

When you build a WCF service using Visual Studio 2008 using the WCF Service Library project template, Visual Studio automatically hosts the service library using the WcfSvcHost.exe application. However, when you're simply hosting this service in another service host (like IIS) you don't need this WcfSvcHost.

To make this even more annoying, if the service configuration is incorrect (why would you want to fix something you're not using anyway???) you will see this warning when starting to debug "The target assembly contains no service types. etc...":

 image

This is actually caused by the WcfSvcHost searching your assembly for service types...

There is an easy way to get rid of this, simply delete the app.config file in the service library. You don't need config files in service libraries anyway. Beware, there might be useful configuration information like connection strings, so copy these over to your host's config before deleting.

I tried simply deleting the service configuration from the config file, but the tool still insists in you configuring the service, so this doesn't help. If you still need a .config file in your service library, avoid the WCF Service Library template, use the normal library project instead and add references to System.ServiceModel and System.Runtime.Serialization.

Or you can try to delete the following line from your project:

<ProjectTypeGuids>{3D9AD99F-2412-4246-B90B-4EAA41C64699};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

This deletes the WcfSvcHost from starting.

Doing Demos with Visual Studio

 

With the launch and TechDays coming up in Belgium I really like this blog post from "The Moth" (Daniel Moth that is) about setting up Visual Studio for demos:

http://www.danielmoth.com/Blog/2008/03/abcdefghi-of-setting-up-visual-studio.html 

A must read!

You should also read this post (same Moth):

http://www.danielmoth.com/Blog/2008/02/10-tips-on-how-to-setup-your-laptop.html 

BTW: I couldn't agree more with the 2 spaces instead of tab argument!