Welcome to MSDN Blogs Sign in | Join | Help

Building A Casual Game in Silverlight

Technorati Tags:

del.icio.us Tags:

If you attended MIX08 you would have had a free sample copy of my Silverlight 2 book in the attendee bag. The book has 3 chapters, one on XAML, one on Silverlight 2 in Visual Studio and one on building Silverlight 2 controls.

Frankly, I sometimes wonder why I spend so much time writing books on technology (it's certainly not for the money, unless you have aspirations to be a thousandaire), but occasionally someone comes along and makes my day.

Cigdem Patlak Uzun (aka Crocus Girl) has doen this by taking the sample sliding blocks puzzle from my Silverlight 2 book and turned it into a proper casual game. She's done a terrific job, and its well worth checking out.

Click the image here for more.

She's turned my simple 4x4 grid with a fixed picture into one that can be 4x4 or 2x2, as well as having the facility to upload your own pictures. It keeps track of your cumulative moves to give you a 'score' and has a much prettier UI (not to mention picture) that the one that I used!

Cigdem's blog is a great read, you can find it at http://crocusgirl.wordpress.com. If you have any questions about the app (and maybe want the source code?) get in touch with her there :)

 

Nice job Cigdem!!! :)

Search::Redefined - Silverlight and Yahoo! Japan

I spend a lot of time and miles evangelizing Silverlight, and sometimes it can be painful to see the amazing things that are being done with it, but that I cannot share until they are ready to go.

One such has been what I have been working on is with Yahoo! Japan. Finally it can see the light of day. Yahoo! Japan are the biggest website in Japan, and with typical Japanese flair they want to redefine the entire search experience.

Well they've done it. I can't wait to see more sites innovating like this.

Anyway, take a look here: http://www.microsoft.com/japan/products/expression/creatorsEX/gallery_y.html

...and you'll see it in action. View the video at the bottom of the page.

The live site should be ready to go in a few weeks, but watch the video and see what they've been doing.

Makes the typical search experience of a text block followed by a list of flat HTML text seem boring now, doesn't it? :)

Ganbarre!

 

gallery_y_01_lgallery_y_02_l

Silverlight: Great showcase of Silverlight 1 wins, and information on updates...

Technorati Tags:
   
del.icio.us Tags:

While many among you are focusing more on Silverlight 2, I still strongly recommend that you look at Silverlight 1 for your development needs. If you weren't at MIX, there's a great showcase video (on youtube no less) that shows some of the terrific stuff that is already out there on Silverlight 1.

Here it is:

There's some great stuff in here, my favorite I think being the Korean MNET site, which provides a Silverlight front end to 2million+ pop videos, providing unintrusive advertising, interaction, search engine, Korean IME, styling and more.

And this was build in Silverlight 1!!!

So, if you want to get ahead on SL2 development, there's plenty of goodness that you can deliver today on the RTM Silverlight 1.

Additionally, we've released several service releases of Silverlight 1 since September. Details of them can be found at the following links:

Release History

· Silverlight 1.0 GDR (build 1.0.30401.00) Released April 4, 2008

· Silverlight 1.0 GDR (build 1.0.30109.00) Released Jan. 15, 2008

· Silverlight 1.0 GDR (build 1.0.21115.0) Released Nov. 20, 2007

· Silverlight 1.0 (build 1.0.20816) Released Sept. 4, 2007

Related Links

Enjoy!

Live IT : I'm speaking at Tech ED Israel Tomorrow

If you happen to be hanging out in Eilat, Israel tomorrow, I'm speaking on 'Go Gold With Silverlight' tomorrow afternoon at 2PM local time. I'll be going into detail on what Silverlight is, and where it fits in with Microsoft's overall UX strategy. I'll be focussing on the connectivity aspects in Silverlight 2, showing some demos of how Silverlight can interact with various server technologies including using AJAX and J2EE. It should be fun! I did the Silverlight part of the keynote today with a Mac on stage, and tomorrow I'll be coding in Java. I'm afraid that they'll throw me out!!! ;)

Some pictures: http://www.flickr.com/photos/techedisrael/

And for some R&R, Eilat has a place that you can go swimming with Dolphins....cool, huh? http://www.dolphinreef.co.il/Default.aspx?tabid=27

A quick note on Silverlight Evangelism...and a great blog on Business Development of Silverlight

del.icio.us Tags:

Technorati Tags:

Working for Microsoft is something that I'd recommend to anyone that is interested in technology. I work with the Developer Platform Evangelism team, which, if you're a geek like me, is a great place to be because it lives at the intersection of the Product Development, Marketing and Business Development axes.

The former of these two are probably well know to the masses of developers, designers, devigners and deselopers among you, but I get many questions about what is involved in the third. Too many times I've had conversations with friends to say "No, it's not being a salesman!" , so now my colleague and friend Chris Carper, a member of the Silverlight business development team has started a blog on Silverlight bizdev. Check it out at: http://silverlightbiz.blogspot.com/

Posted by lmoroney@microsoft.com | 2 Comments
Filed under:

Silverlight Dynamic Languages in Visual Studio

    

Silverlight's support of Dynamic Languages is really cool, but, as there is no template in Visual Studio or Expression Blend that supports them it might be a little difficult for you to get up and running quickly. So, I wanted to put together this blog posting to show you how you can use them within Visual Studio in a common (or garden) Web site project. It's a pretty lengthy tutorial for a Hello World applicaiton, but I'm assuming that you are as unfamiliar with Dynamic Languages as I was when I started figuring them out.

It's something I've been working on for my Silverlight 2 book, Hope you like it! Do note that all proceeds from this book will go to children's education(*), so be sure to buy lots of copies.

Silverlight 2 adds support for the use of dynamic languages, which are defined as programming languages that execute many features at runtime that other languages such as C# execute at compile time. Such behaviors include things such as extending objects and definitions, modifying the type system and more. This approach is designed to give dynamic languages a simple approach for learning through a ‘run-evaluate-print’ loop with lots of trial and error as you develop.

Silverlight 2 supports three of the more popular dynamic languages: Ruby, Python and dynamic, managed JavaScript. The SDK provides a tool called Chiron.exe that allows you to work with dynamic languages.

 

(*) My children's education of course! :)

 

Getting Started

The Chiron tool is easiest to use if you have a specific application directory structure set up for your application. In this section we’ll go through how to do this step by step.

First launch Visual Studio and create an empty Web Site by selecting New Web Site from the File menu. You’ll see Empty Web Site as an option on the New Web Site dialog.

clip_image002

 

This will create an empty directory that Visual Studio can access as a Web Site. However, we will be using Chiron to run the site, but creating the pages, code etc is easier in Visual Studio.

From the Solution, right click on the project folder and select ‘Add New Item...’ – this will give you the Add New Item dialog that you can use to create a new HTML page, so select the HTML page option and give it the name Default.html.

clip_image004

 

This will give you a basic HTML page, which you should edit to turn into a page that will host the Silverlight application. Here’s the code for such a page.

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>Dynamic Silverlight Test Page </title>
  <style type="text/css">
    html, body {
      height: 100%;
      overflow: auto;
    }
    body {
      padding: 0;
      margin: 0;
    }
    #silverlightControlHost {
      height: 100%;
    }
  </style>
</head>
<body>
  <div id="silverlightControlHost">
<object data="data:application/x-silverlight," 
    type="application/x-silverlight-2-b1" 
    width="100%" height="100%">
      <param name="source" value="app.xap"/>
      <param name="background" value="white" />
      <param name="windowless" value="true" />
    </object>
    <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
  </div>
</body>
 

This uses the <object> tag approach to host Silverlight in the page. It’s bare bones, so doesn’t include the code to provide an install experience if Silverlight isn’t present on the system.

Keep a note on the source parameter which is set to app.xap. Chiron will build this for you, which you’ll see in a moment. In order for it to have this name, your code file will need to be called app. First you’ll look at how do build your application with IronPython, and an app.py file, and later you’ll see how to do the same functionality with IronRuby and Dynamic JavaScript.

Next, create a directory within your web called app. Within this, select ‘Add New Item’, and select the XML File template, and call the file app.xaml.

Here’s some simple XAML that you can put into this file:

<UserControl
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="System.Windows.Controls.UserControl"
    x:Name="Page"
    >
  <TextBlock
     x:Name="txtMessage" TextWrapping="Wrap" 
     Foreground="Black" Text="Hello World," >
  </TextBlock>
</UserControl>

This defines a simple UserControl object that contains a TextBlock called txtMessage. This TextBlock contains the text “Hello World,” – note that it ends with a comma. You’ll see why in a moment!

Now let’s add the IronPython code file. Again right click on the app folder within your Web site, and select ‘Add New Item…’. From the dialog, select Text File and call it app.py (‘py’ is the extension for python).

As a quick sanity check your solution should look like this:

clip_image006

Now let’s edit your python code file to make it do something a little interesting.

Here’s the code:

from System.Windows import Application
from System.Windows.Controls import UserControl
 
def handleClick(sender, eventArgs):
    sender.Text = sender.Text + " from Python!"
 
class App:
    def __init__(self):
        self.scene = 
          Application.Current.LoadRootVisual(UserControl(), 
                                             "app.xaml")
 
    def start(self):
        self.scene.txtMessage.MouseLeftButtonUp += handleClick
        
App().start()

If you’ve been writing Silverlight applications in C# or VB, the syntax will be roughly familiar to you, so for example the line

from System.Windows import Application

is equivalent to the C#

using System.Windows;

and then referring to the Application class in code.

The code then defines a python class, called App and sets the ‘scene’ object for this app by loading the xaml file that you defined earlier. As part of this class definition it defines the startup event hander with def start(self): and specifies the code to execute within this handler. This code defines the event handler for the MouseLeftButtonUp event on the TextBlock control called txtMessage that you defined earlier. The event hander is called handleClick.

The event handler code itself is here:

def handleClick(sender, eventArgs):
    sender.Text = sender.Text + " from Python!"

This adds the text “ from Python!” to the end of the Text property of its sender (which in this case is the TextBlock) upon being called.

Configuring Visual Studio to use Chiron

To run this application you’ll use Chiron. You can configure Visual Studio to launch Chiron by right clicking on the project file in Solution explorer (note, use the Project file and not the Solution file – the Project is usually the first child of the Solution) and selecting Property Pages from the pop up menu.

From the property pages, select Start Options, and then select Start external program. Use the ellipses button to brose to the location of Chiron.exe which should be in C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Tools\Chiron.exe.

Enter ‘/b’ in the Command line arguments setting, and then enter the location of the web site in the Working Directory setting.

You can see it here

clip_image008

 

Now you can execute your dynamic Silverlight application by pressing F5 in Visual Studio.

Chiron will launch and you’ll see this in a command prompt window:

clip_image010

This shows you that the application is accessed via http://localhost:2060. Visual Studio will also launch a browser at this address, which gives you a listing of the files within the web directory.

clip_image012

Select Default.html to see your dynamic Silverlight application. You’ll see your ‘Hello World’ message.

clip_image014

Clicking the ‘Hello World,’ text will then add ‘ from Python’ to the block as shown here

clip_image016

While this is, of course, an extremely simple application, it demonstrates how the Dynamic Language Runtime works in Silverlight, and how to configure Visual Studio to use Dynamic Languages!

Posted by lmoroney@microsoft.com | 3 Comments
Filed under:

Determining Silverlight Installation Metrics at your site

del.icio.us Tags:

Technorati Tags:

Following lots of requests from folks inside MS, I wrote this paper as a very simple guide to determine installation metrics. No reason why it shouldn't see light of day, so share and enjoy! :)

 

Introduction

This paper is intended to provide a methodology for customers to measure the level of Silverlight adoption amongst their customer base. Silverlight does not write to the HTTP_USER_AGENT string, so server logs will not contain any direct data for Silverlight installations. However, a very straightforward process may be used on web pages on the customer site to determine Silverlight penetration. This paper discusses two of these methods.

Overview.

The procedure is very straightforward. In both cases, client-side JavaScript and Dynamic HTML are used. The JavaScript is used to detect the presence of the Silverlight plug-in on the browser. The server hosts two images, one which is loaded if Silverlight is present, one which is loaded if Silverlight is not.

In this example, the images are called ‘red.gif’ and ‘green.gif’. Server logs can be used to see the traffic to each of these images. If R is the total traffic to ‘red.gif’ and G is the total traffic to ‘green.gif’, then R+G is the total traffic and [100* G/(R+G)] gives us the total percentage of traffic that comes from browsers with Silverlight installed.

Please note that these samples use red.gif and green.gif for illustrative purposes only. In a production system, it is recommended to use a 1 pixel by 1 pixel image which is not visible to the user.

[The assumption being made here is that R and G can be measured in Unique Users (UU)]

Method 1 – Using Silverlight.js.

This method involves the customer putting ‘Silverlight.js’ on their site. This JavaScript library is approximately 8Kb in size, and contains functions that are heavily tested across different browsers and operating systems.

It includes a variable: Silverlight.available which evaluates to True is Silverlight is installed and False if Silverlight is not.

This can then easily be used within HTML like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Silverlight Test Page 1</title>
    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript">
        function doTest()
        {
            if(Silverlight.available)
            {
                imgContent.innerHTML = "<img src='green.gif' />";
            }
            else
            {
                imgContent.innerHTML = "<img src='red.gif' />";
            }
        }
    </script>
</head>
<body onload="doTest()">
    <div id="imgContent"></div>
</body>

</html>

This HTML contains a DIV element called imgContent. Upon the page loading, the doTest() function is called. This checks to see if Silverlight is available. If it is, it sets the innerHTML property of imgContent to contain an HTML Image element that has its source set to the URL of either the red or green image. This generates a call to the image, and thus loggable traffic on that image.

The logs can then be inspected as outlined in the overview section.

Method 2 – No Silverlight.js

A similar approach may be taken if Silverlight.js is not present. The advantage of this is that the customer does not need to distribute or update the Silverlight.js file. The disadvantage is that it is a little more complex, and will require maintenance as new Silverlight versions, browser versions, and operating systems platforms are supported.

It follows a similar approach to method 1 in that it determines if Silverlight is installed. If it is, then the imgContent div will have its innerHTML set to an image referencing the green.gif URL, otherwise it will be set to an image referencing the red.gif URL.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Silverlight Test Page 2</title>
    <script type="text/javascript">
    function doTest()
    {
        var container = null;
        try {
            var control = null;
            if (window.navigator.userAgent.indexOf('MSIE') >= 0) {
                // For Internet Explorer, Create an ActiveX Object
                // And assign it to the 'control' variable.
               // If Silverlight is not installed, this should throw an error
                control = new ActiveXObject('AgControl.AgControl');
            }
            else {
             // For FireFox/Safari
             // Check to see if the plug-in is present
                    
             if (navigator.plugins['Silverlight Plug-In']) {
             {
                container = document.createElement('div');
                document.body.appendChild(container);
                container.innerHTML= 
                   '<embed type="application/x-silverlight" src="data:," />';
                control = container.childNodes[0];
            // If the plug-in is present, then we should have gotten this far
            // without an error. If we threw an error, it is caught later on
             }
             else
             {
                        // plug-in is not present, so we go red
                        imgContent.innerHTML = "<img src='red.gif' />";
             }
            }
           }
           if (control) {
                // plug-in is present and we were able to instantiate
                imgContent.innerHTML = "<img src='green.gif' />";
           }
           else
           {
                // we weren't able to instantiate, so we say it isn't present
                imgContent.innerHTML = "<img src='red.gif' />";
           }
         }
        catch (e) { 
            // we hit an error so we say it isn't present
            imgContent.innerHTML = "<img src='red.gif' />";
        }

        // Let's clean up
        if (container) {
           document.body.removeChild(container);
        }

    }
    </script>
</head>
<body onload="doTest()">
        <div id="imgContent"></div>
</body>
</html>

As can be seen in the code, the approach is to try to create an instance of the plug-in on the page using DHTML. If this fails, or if the plug-in is found to not be present by checking the browser-dependent methods, Silverlight is deemed to be not installed. If it succeeds, Silverlight is deemed to be installed. The appropriate ‘red’ or ‘green’ URL calls are then made, and their logs can be checked against in the way discussed in the overview.

Summary

This paper discussed two methods for determining Silverlight penetration at a client site, by using web pages with JavaScript and Dynamic HTML. The first approach used libraries within Silverlight.js, and the second bypassed using this file. At time of writing the first approach is recommended as the Silverlight.js library is fully and extensively tested for cross-browser and cross-platform correctness, and thus the most accurate results may be attained.

Posted by lmoroney@microsoft.com | 2 Comments
Filed under:

DeepZoom in C# - Not just possible, but easy

DeepZoom with the MultiScaleImage control

Technorati Tags: ,,

del.icio.us Tags: ,,

 

DeepZoom is a new technology which has been added to Silverlight 2 which gives you a new and unique way of managing images within your application. It is implemented by the <MultiScaleImage> element in XAML, which, as its name suggests, gives you the facility to control scale and zoom of your images, with Silverlight providing a huge virtual space on which these images can be drawn.

This is best described by example. Here you can see an image of a kids science project.

clip_image002

Now this doesn’t really look too fancy. So what’s all the fuss. Well, on this application if you drag the mouse wheel, you can zoom in or out. So, if you look at the next figure, you’ll see another view of this where I’ve zoomed out of the orange, and am showing where this image is relative to another image.

clip_image004

 

If you look closely at the center of the orange above, you’ll see that the first image is embedded within the orange at the center. You can zoom out from this again, to get this image

clip_image006

 

As you can see the entire second image is little bigger than a pixel in the third image, and the entire first image is little bigger than a few pixels in the second. It’s hard to do this justice with these stills, but it has to be seen to be believed, and when you play with it, you’ll see why the technology is called DeepZoom…it allows you to arrange pictures so that you can zoom in and out of them very easily, painting them on a giant, scalable canvas.

Using the Deep Zoom Composer

But how do you build an application like this? It’s pretty simple to do a basic one – you simply use the MultiScaleImage control and point it at a .BIN file that contains metadata about the images. You create this .BIN file using the DeepZoom composer tool, which may be downloaded from the Microsoft Download center.

You can see the composer tool here:

clip_image008

This tool follows a simple workflow of Import followed by Compose followed by Export.

So, first you should select the Import tab, and select ‘Add Image’ to pick a picture, and repeat for the number of pictures you want to use. You can see in Figure 11-21 that I’ve selected three images.

The next step is to Compose, which you will do with the compose tab. On this tab you place images on the design surface and then zoom in and out and place others. So, for example if you look at Figure 11-22, you’ll see where I’ve placed one image and zoomed into the eye.

clip_image010

Now if you place a new image, it will be placed at its normal resolution once the Silverlight component is zoomed to the level that you are currently at in the composer. So if you look at the next picture, you’ll see where the image has been placed within the eye. Later, when you run the application, you would have to zoom directly into the eye to see this image, and it will be tiny until you zoom further into it. clip_image012

In this simple example we’ve just added one image to appear when zoomed in on another. The tool allows us to build far more complex applications, but for the purposes of this sample, what we have will do. We are now ready to go to the third step – exporting the details.

You can see this here:

clip_image014

To do this, you simply need to give the project a name and export it to the specified location.

Once this is done, you’ll see two files and a folder created in the output directory. The first file is the project file for the Deep Zoom composer. The second is SparseImageSceneGraph.xml which is a configuration file that simply defines each image and the location of each image within the other in the different Zoom levels. So, for example you can see the scene graph for the 2 picture XAML here:

<?xml version="1.0"?>
<SceneGraph version="1">
  <AspectRatio>1.33333333333334</AspectRatio>
  <SceneNode>
<FileName>C:\Code\SLBook\Chapter11\DZCSample
     \source images\DSCN2961.JPG</FileName>
    <x>0</x>
    <y>0</y>
    <Width>1</Width>
    <Height>1</Height>
    <ZOrder>1</ZOrder>
  </SceneNode>
  <SceneNode>
<FileName>C:\Code\SLBook\Chapter11\DZCSample
     \source images\DSCN2959.JPG</FileName>
    <x>0.451782754964542</x>
    <y>0.313488814592021</y>
    <Width>0.00099432659277551</Width>
    <Height>0.00099432659277551</Height>
    <ZOrder>2</ZOrder>
  </SceneNode>
</SceneGraph>

It’s pretty straightforward. It contains the aspect ratio for the master image (derived from the dimensions of the first image) and then each image becomes a SceneNode. The first image is the first scenenode, and it is defined as being located at position 0,0, and is a normalized image – i.e. its width and height are set to ‘1’. All other image sizes and locations are then set relative to this. The second image, as you will see is at approximagely 0.45 on the x axis, and 0.31 on the y axis and is sized at approximately 0.00099 on X and Y relative to the first image, thus if you zoom into the first image to approximately 10,000x the original size, you’ll see the second image. It is ZOrdered at 2 (while the first is at 1), meaning that it will be drawn on top of the first image.

In addition to this, the Deep Zoom composer slices the image into tiles so that you don’t have to load every tile for every zoom level, giving you nice efficiency when you are dealing with large images. When you are zoomed out, you will have a ‘small’ tile, indicating the apparent resolution for being zoomed out. When you zoom into the full resolution of the image (or beyond), you will only see a portion of the image, and thus you will only get the tiles representing the part of the image that you see, thus saving bandwidth and download time. The Info.bin file contains all the details of the tiles and where they are relative to the main image. You’ll find it in the subdirectory, along with a number of other directories containing the images.

Building your first Deep Zoom project.

To use this in an application, create a new Silverlight Application. Before doing anything, you should compile the default application. This will create the ClientBin application in the Web Application part of the solution. When this is done, close the solution.

Now, use Windows Explorer to copy the directory containing the info.bin file and the subdirectories containing the fragmented images into the ClientBin directory of the web application. When this is done, re-open the solution. You should see your project explorer will look something like this:

clip_image016

Now to render the Deep Zoom content, you simply add a MultiScaleImage to your Page.xaml, and set its Source property to the location of the info.bin file (in this case it is in /dzcsample/info.bin), as well as its desired width and height.

Here’s what your Page.xaml will look like:

<UserControl x:Class="DZCSampleApp.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Canvas>
        <MultiScaleImage Source="dzcsample/info.bin" 
          Height="300" Width="400" />
    </Canvas>
</UserControl>

So now when you run this application, the MultiScaleImage control will render the top element in the SceneGraph, zooming into it from a 1x1 picture to the width and height specified (400x300 in this case).

You’ll notice that there is no automatic mouse activity, so you cant pan or zoom the image. We’ll look at how to do this in the next section.

Using the Mouse and Logical Co-Ordinates in Deep Zoom

The MultiScaleImage is just like the other components in Silverlight in that it can declare the functions that should be used to handle events. So, to pan around the image you will use the typical mouse events of MouseLeftButtonDown, MouseLeftButtonUp and MouseMove in a very similar manner to drag and drop on any control.

So first, lets take a look at the XAML for the MultiScaleImage that defines these events:

<UserControl x:Class="DeepZoomSample.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="640" Height="480">
    <Canvas>
        <MultiScaleImage x:Name="dz" Source="dzcsample/info.bin" 
            MouseLeftButtonDown="MultiScaleImage_MouseLeftButtonDown" 
            MouseLeftButtonUp="MultiScaleImage_MouseLeftButtonUp" 
            MouseMove="MultiScaleImage_MouseMove" 
            Height="480" Width="640"></MultiScaleImage>
    </Canvas>
</UserControl>

And now we’ll look at each of these event handlers in more detail. First, there’s some code that is shared across them all, and used for tracking the current state of the mouse and the currently viewed co-ordinates of the MultiScaleImage.

bool dragging = false;
 
double dx = 0;
 
double dy = 0;
 
Point p0;
 
Point p1;
 
Point pLast;

 

So now, let’s examine what happens when the user presses the mouse button on the image:

private void MultiScaleImage_MouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
        {
            dragging = true;
            p0 = dz.ElementToLogicalPoint(new Point(0, 0));
            p1 = dz.ElementToLogicalPoint(new Point(640, 480));
            dx = 0;
            dy = 0;
            double x = e.GetPosition(null).X;
            double y = e.GetPosition(null).Y;
            pLast = dz.ElementToLogicalPoint(new Point(x, y));
            
        }

So, when the mouse button is held down, you are going to assume that the user is dragging the mouse, so we set the dragging Boolean to true. Then we want to get the current co-ordinates of the image that are visible. Remember that the top image is defined as being at x=0 and y=0, and that its width and height are both set to 1. These are the logical co-ordinates and the logical dimensions.

In Silverlight if we want to derive the logical co-ordinates of the top left of the window and the bottom right, we can get them by using the ElementToLogicalPoint method. If you pass a physical co-ordinate to this, the logical result will be returned. So, if you can imagine that you are zoomed into a picture and you’ve panned that picture around a little, then if you call this API for physical point (0,0) – i.e. the top left of what you can see then the logical point representing that location on the full image will be returned. To get the bottom right you do the same for the point at the current width and height of the physical display (in this case 640x480).

We want to track how much we’re changing on X and Y, so we set the variables dx and dy to zero. We’ll see more of this in a moment.

Finally we’ll also want to get the logical co-ordinates of the mouse pointer, so we do this with the ElementToLogicalPoint API call and passing the current mouse position (which can be derived from the MouseEventArgs object that is passed to this function), and load the results into the pLast variable.

Now that the mouse is down, once we start dragging what happens next? We want the image to pan around and follow us. Here’s the code to achieve this:

 

The MouseMove event will fire whether the button is held down or not, so we use the dragging variable to indicate whether or not we’re dragging. So, if we’re presently dragging, and if we presently have some event args, the rest of the code will execute.

In this case we pull the current co-ordinates of the mouse and assign their logical equivalents (received using the ElementToLogicalPoint method of the control) to the pCurrent point. Now, if the pLast is not null, then we’re dragging and the mouse has moved from the previous point. So, to get the overall change in logical co-ordinates that occour from moving the mouse from the last point to the current point, we simply calculate them by finding the delta from the current from the previous on both X and Y. Then we set the Origin property of the MultiScaleImage to the initial position changed by the delta on both X and Y. This will have the effect of ‘moving’ the image as we drag the mouse, when we are in fact just changing the co-ordinates of the image origin (i.e. its top left hand corner). Once done, we set the Last position to the Current position, so that upon the next mouse move we’ll calculate relative to this point, and not the one where the mouse was first held down.

Finally when the user releases the mouse you want to reset everything, which is pretty straightforward. Here’s the code:

private void MultiScaleImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            dragging = false;
            p0 = new Point();
            p1 = new Point();
            pLast = new Point();
            dx = 0;
            dy = 0;
            
        }

So with these three simple functions you’ve now added the facility to drag your way around the image, panning it regardless of its zoom level. In the next section you’ll see how to use the mouse wheel to zoom in and out of the image and thus reveal the hidden images that were hidden when you were at the ‘outer’ zoom levels.

Creating the Zoom functionality with the MouseWheel

One problem with building Deep Zoom applications is that the defacto standard control for zooming in and out of an item is the Mouse Wheel, but, Silverlight and .NET don’t handle events on the mouse wheel. So what can we do? There are 2 options. The first is to use JavaScript, and not C# as the browser can capture the mouse wheel and fire an event upon rolling it. The second is to use the browser bridge to Silverlight to have the browser capture the event, and then inform .NET that it has done so, and then the code to handle it is implemented in .NET.

This is a lot easier than it sounds!.

First of all, you’ll have to ensure that you are able to use the browser APIs in Silverlight, so be sure to have the following line to include them:

using System.Windows.Browser;

Then, within the page constructor, make sure that you are registering the control to be scriptable. This exposes methods of the control that are attributed as ScriptableMember to JavaScript. Here’s how you do this:

public Page()

{

    InitializeComponent();

    HtmlPage.RegisterScriptableObject("MySilverlightObject", this);

}

Next, on your page, you’ll want to capture the mouse wheel events. Do this by first adding a ‘handleLoad’ call to the <Body> tag to ensure that your JavaScript code will run when the page is rendered:

<body style="height:100%;margin:0;" onload="handleLoad();">

...

</body>

Then, within the handleLoad JavaScript function you’ll set up the event

function handleLoad()

{

    window.onmousewheel = document.onmousewheel = onMouseWheel;

    if (window.addEventListener)

    {

        window.addEventListener('DOMMouseScroll', onMouseWheel, false);

    }

}

This defines the onMouseWheel JavaScript function to execute whenever you scroll the mouse wheel.

function onMouseWheel()

{

    if(!event)

    { 

        event = window.event;

    }

    var slPlugin = $get("Xaml1");

    slPlugin.content.MySilverlightObject.dz_MouseWheel(

    event.clientX, event.clientY, event.wheelDelta);

}

This function simply gets a reference to the Silverlight component (in this case it is called Xaml1 when it is created), and then calls a function within the code-behind for that. You call this by using the <ComponentName>.content.<ObjectNameDefinition>.<FunctionName> syntax.

The <ComponentName> is the var that you defined in JavaScript to be a reference to the Silverlight object.

The <ObjectNameDefinition> is the name you defined for the object back when you registered it (take a look at the Page() constructor to see it).

The <FunctionName> is the name of the function that you want to call. This function needs to be attributed correctly in order for JavaScript to ‘see’ it. In this case you are calling the dz_MouseWheel function, so let’s take a look at it:

        [ScriptableMember]
        public void dz_MouseWheel(double x, double y, int delta)
        {
            double dZoomFactor=1.33;
            if (delta < 0)
                dZoomFactor= 1/1.33;
            Point pz = dz.ElementToLogicalPoint(new Point(x, y));
            dz.ZoomAboutLogicalPoint(dZoomFactor, pz.X, pz.Y);


            
        }

First, as you can see, it is attributed as a ScriptableMember, meaning that JavaScript can see it and call it. The JavaScript function send in the current mouse co-ordinates and the delta that came from the zoom. This should return a positive value if you are wheeling forwards, and a negative value if you are wheeling backwards.

The zoom factor per wheel movement is defined as 33% (but you could of course define whatever you want), so the dZoomFactor variable is set to 1.33 if you are going forwards, and 1/1.33 if you are going backwards.

Next you want to zoom around the current mouse co-ordinates, which is very simple to do by just converting the mouse co-ordinates to a logical point using the ElementToLogicalPoint method of the MultiScaleImage control. Now that you have the co-ordinates and the zoom factor, you simply call the ZoomAboutLogicalPoint method to cause the MultiScale image to zoom in and out.

And that's it! You're now ready to DeepZoom with the best of them! :)

Posted by lmoroney@microsoft.com | 6 Comments
Filed under:

2 New books in one week! and a great DeepZoom in C# tutorial on the way...

For those of you who were at MIX this week, you would have received a nice free sample copy of my "Introducing Silverlight 2: First Look" book. This sample has 3 chapters from the finished book, giving you a tour of XAML, as well as an introduction to building Silverlight applications and controls using Visual Studio. Here's a link to the full book -- and I'm aiming for a late May, early June release.

Also this week, my newest APress book was released. It's called Beginning Web Development, Silverlight and ASP.NET AJAX From Novice to Professional and is available now.

I'm really proud of this book, and think you'll really enjoy it. I've tried to take a slightly different approach in it, and its aim is to take you on a tour of the myriad of Web technologies that are out there, giving you a really firm grounding in everything that you can do to build Web applications with Microsoft technology.

It's not an in depth reference on any one technology, more a smorgasbord of everything that you need to know to get started on the road of being a super-effective professional. You won't become a CardSpace uber-expert after reading this book, but you will gain enough hands-on, real-world experience to have a grasp on the technology and start using it for your site. Part One of the book is aimed at someone who isn't fully versed in the Web, taking them from the birth of the web through static HTML, through generation of HTML from a smart server, and the evolution of ASP.NET as a result. Part Two then takes us into the Next generation technologies: WPF, WCF, Workflow, Cardspace, AJAX, ASP.NET AJAX and finally Silverlight. By the time you're done, you'll be animating WPF, consuming WCF services, building casual games in Silverlight, extending JavaScript with your own objects...what's not to love? :)

I've been heads-down on MIX and other important Silverlight activities for the past few months so no posting...I'll make it up to you with a C# DeepZoom tutorial very very soon -- watch this space!

Here's the Chapter Breakdown:

PART ONE: Understanding and Building Web Applications

  1. Introduction to Web Development
    1. The Internet and the Birth of the Web
    2. Going beyond the Static Web
    3. The Arrival of ASP.NET
  2. Basics of Web Development with ASP.NET
    1. Using Visual Studio
    2. Architecture of ASP.NET
  3. Web Forms with ASP.NET
    1. Understanding Page Processing
    2. Looking at Web Forms
    3. Processing Web Forms
    4. Pages and Controls
    5. The Page Object
  4. Data Binding with ASP.NET
    1. What is ADO.NET
    2. SQL Server 2005
    3. Using ADO.NET to build Data-Driven Applications
    4. Data Binding with Server Controls
  5. ASP.NET Web Services
    1. Web Services Architecture
    2. Building a Web Service
    3. Creating a Service CLient
  6. Deploying your Web Site
    1. IIS and what it does
    2. Manually deploying Applications

PART TWO: Next Generation Technologies for Web Development

  1. .NET 3: Windows Communication Foundation
    1. WCF and Productivity
    2. WCF and Interoperability with WS-*
    3. WCF and Service Orientation
    4. Programming WCF
  2. .NET 3: Windows Presentation Foundation
    1. XAML
    2. Expression Blend
    3. Building WPF Applications with Blend and Visual Studio
  3. .NET 3: Windows Workflow Foundation
    1. Using WF
    2. Using Visual Studio to build Workflows
    3. Out-of-the-box Activities
    4. Workflow and the Web
  4. .NET 3: Cardspace
    1. Using Cardspace
    2. Creating a Web site that uses Cardspace for authentication
  5. AJAX and the User Experience
    1. A brief history of AJAX
    2. Improving UI with AJAX
    3. Build a Forward Cacheing sample with AJAX
  6. AJAX Extensions for .NET
    1. ASP.NET AJAX Overview
    2. Getting Started with ASP.NET AJAX
    3. Building AJAX Applications with ASP.NET AJAX
    4. Using AJAX with Web Services (POX, REST)
  7. AJAX Scripts and Services
    1. Using ScriptManager
    2. Partial Page Rendering
    3. Using Web Services, Applicaiton Services and Profile Data from AJAX
  8. JavaScript Programming with ASP.NET AJAX
    1. Using Object Oriented Features (Namespaces, Inheritance, Interfaces and Reflection) in JavaScript
    2. Adding type extensions to JavaScript
    3. Date, Error, Number and string extensions
  9. Enhancing the Web Experience with Silverlight
    1. What Silverlight is and how it works
    2. Programming the Silverlight control
  10. Programming Silverlight with XAML and JavaScript
    1. A tour of XAML
    2. Using JavaScript to program Silverlight
    3. Building a simple Casual Game in Silverlight

 

Posted by lmoroney@microsoft.com | 2 Comments
Filed under:

Introducing Silverlight Book: Code Update

If you're reading Introducing Silverlight and are having some trouble with the code in Chapter 8 for the tracking textblocks sample, there's a missing line of code that defines a global variable.

Here's the full C# code for the TextBlocks sample:

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Controls;
   4: using System.Windows.Documents;
   5: using System.Windows.Ink;
   6: using System.Windows.Input;
   7: using System.Windows.Media;
   8: using System.Windows.Media.Animation;
   9: using System.Windows.Shapes;
  10:  
  11: namespace SilverlightProject2
  12: {
  13:     public partial class Page : Canvas
  14:     {
  15:         string strCurrentText;
  16:         public void Page_Loaded(object o, EventArgs e)
  17:         {
  18:             // Required to initialize variables
  19:             InitializeComponent();
  20:             foreach (TextBlock tt in this.Children)
  21:             {
  22:                 tt.MouseEnter += new MouseEventHandler(OnEnter);
  23:                 tt.MouseLeave += new EventHandler(OnLeave);
  24:             }
  25:         }
  26:         public void OnEnter(object sender, MouseEventArgs e)
  27:         {
  28:             TextBlock tt = sender as TextBlock;
  29:             strCurrentText = tt.Text;
  30:             tt.Text = "I am in : " + strCurrentText;
  31:         }
  32:         public void OnLeave(object sender, EventArgs e)
  33:         {
  34:             TextBlock tt = sender as TextBlock;
  35:             tt.Text = strCurrentText;
  36:         }
  37:     }
  38: }

 

And here's what the final result looks like:

image

Many thanks to Jeff Paries for catching this one! :)

MIX08: The Next Web Now

Technorati Tags: ,

del.icio.us Tags: ,

The MIX08 Site is now online and registration for the hottest conference of the year is open. MIX tends to sell out very quickly,