Friday, April 25, 2008

Next Project - Port SimpleViewer to Silverlight

Having run out of ideas on how further to exploit Deep Zoom, I am going to now focus my energy on porting the closed-source flash based SimpleViewer to Silverlight. Again, my objective is to learn Silverlight, so I will try to push some boundaries (if required). As part of this exercise, I will try to stick to the original goal of SimpleViewer, that is keep the download as small as possible. The current version (1.8.5) of SimpleViewer is only 17k and that is what I am aiming for. This, of course, means no using the extended controls, but only what is available in the core Silverlight 2 SDK!

So, why SimpleViewer? I actually use it in my personal blog and have always wanted more control over it. I also want to know what it takes to create the same experience in Silverlight. I am expecting this to be a trivial exercise, but let's see!

My first roadblock!

I wanted to keep everything as dynamic as possible. This means no explicitly specifying the height and width of any control. I was happy to see that the image control provides this capability and is able to work well within the constraints of MaxWidth and MaxHeight. This was all wonderful and perfect for my needs but now I wanted to draw a simple border around the image. Pretty easy...all I need is the dimensions of the image (control), but this is where it got a little complicated. The image control does give access to the dimensions but a little too late. I won't go into the details here but I did post it on the Silverlight.net forum is anyone's interested. By the way this is a great forum and one of the best places to get answers to all your Silverlight questions or issues.

What I discovered is that the image loaded event is not a reliable place to extract the dimensions from the image control. I tried a kludgey workaround by creating a timer and accessing the dimensions from the image control a little later - around 100 milli seconds - but this is definitely not reliable. But at least I had a solution!

While I was playing with it some more, I discovered the SizeChanged event. This also doesn't help if the image dimensions are extracted from the image control itself, but I discovered that the event itself has the size, and that is when I had my solution!

There might be some issues with this so please leave a comment if you find something. I am assuming this is a bug with the image loaded event so, hopefully, it will be fixed in the next release of Silverlight. But, for now, it looks like I can make some "not so kludgey" progress!

MyImage.SizeChanged += (sender, e) => {
if (e.PreviousSize.Width == 0 && e.PreviousSize.Height == 0 && e.NewSize != e.PreviousSize) {
// e.NewSize contains the dimension of the image
// MyImage.Width and MyImage.ActualWidth is unreliable so use e.NewSize instead
DrawBorderAroundImage(e.NewSize);
}
};

4 comments:

Chris said...

Hey there! It's me again, I posted about the highlighting bug, remember? Anyway, I was wondering if you think this strategy could be adapter to solve the highlighting bug.

I'm not so sure just because SizeChanged applies to the Deep Zoom Object as opposed to a SubImage ... any ideas?

Wilfred Pinto said...

Chris,

Didn't know you are still looking for a fix for this bug!

It has nothing to do with SizeChanged. The problem is that I was working with the entire collection rather than the filtered collection. I put a follow up comment in your original post.

Hope this helps!

Wilfred Pinto

Brendon said...

I had the same problem, needing to find out the width and height of a loaded image. This is what worked for me:

Listen to Image.LayoutUpdated. You can there test to see if the width or height is greater than 0. One note, my image had to be visible in order for the ActualWidth or ActualHeight to show up greater than 0.0, but it worked.

I could not get SizeChanged to work for me.

Anonymous said...

Hi,
I also faced the same issue as you originally, and the best work-around is to have a LayoutUpdated listener and to check to see if image.ActualWidth != 0 && image.ActualHeight != 0. A few other nitpickinesses of this: make sure to add the image to a Canvas as opposed to a Grid. You can also render it completely off-screen (e.g. -4000 -4000 and it will work).