Wintellect  

It may be the dog days of summer, but things are hopping here at Wintellect. We just finished another successful Devscovery Redmond, where attendees soaked in lots of Silverlight love and also made a run on the Microsoft company store. If you've never attended a Devscovery in Redmond, it's worth the price of admission just to shop in the company store at employee prices. A big thanks to Microsoft for hosting Devscovery on campus and making all the Wintellect and Infragistics folks and the attendees feel right at home.

We see many of the same faces each year at Devscovery, and this year was no exception. Long-time Devscovery devotee George Handlin made the trip to the west coast and brought along his pal Mik. I think Mik is the first moose (?) to ever attend Devscovery, but I'm not sure. We didn't charge Mik admission. Animals are free at Devscovery.

Jeff, George, and Mik 

I got tickled during a 1-on-1 (special sessions we do at Devscovery in which attendees schedule 1-on-1 time with the speakers) from one of our Russian attendees. She shared with me that "both of my sons are developers. One works for Microsoft. The other programs Linux. We call him our little communist." It was all I could do to not bust out laughing.

Silverlight 2 successfully withstood the Beijing Olympics and is well on the road to RTM. I'm not at liberty to divulge dates, but Microsoft has publicly said that Silverlight 2 will ship this year, and I'm confident that they'll make it. Most of my work these days involves Silverlight, and I can honestly say it's been a long time since I've had this much fun as a developer. One of the things I've been doing is writing new code samples and porting some of my Silverlight 1.0 samples to Silverlight 2. The latest port (pictured below) is my Silverlight Magnifier sample. You can download a version written against Beta 2 here. Just click the left mouse button over the page to display the magnifying glass and drag the mouse to move the glass. Pretty cool effect, especially given that it's done without WPF's handy VisualBrush. This sample and others like it will be featured in my next Wicked Code column in MSDN Magazine.

Magnifier 2 

I have a lot of trips coming up, including one to the PDC in October, where I'll be doing a precon on Silverlight 2 on Sunday, Oct. 26. If you come to L.A. for the PDC, I'd love to see you at the precon. I have some fun stuff to show and you never know what surprises may await you. It's Halloween week, and we might be able to talk Richter into wearing a cute ballerina costume. He modeled a bikini for us at this year's company retreat and it was...well...memorable. Male software developers generally don't look very good in bikinis, but Jeffrey is exceptional in more ways than one.

If you're interested in writing custom controls for Silverlight but need a step-by-step tutorial to get you started, check out my latest column in MSDN Magazine: Craft Custom Controls for Silverlight 2. I had a load of fun writing this one and wrote it because there is so precious little information out there about Silverlight custom controls. The model is pretty simple once you get your arms around it, but as I said in the article, it can seem pretty confusing if you've never built controls for Silverlight or WPF before.

My explanation of Silverlight's Visual State Manager (VSM) in the article was somewhat light because 1) magazine space is limited, and 2) I had to scramble at the last minute to add VSM converage. The article had already been edited and was about to go to print when I learned about the VSM. We considered just leaving the article as-is (as-was?) and putting a big "Beta 1" warning label on the first page. But I couldn't sleep at night knowing the article would be obsolete before it was printed. So, with the support of my editors at MSDN Magazine, I stretched the deadline and did some 11th-hour rewriting. Now that the article is live, I'm really glad I did.

If you'd like to learn more about the VSM, let me suggest an EXCELLENT 4-part tutorial by Silverlight UX guru Karen Corby entitled Parts & States Model with VisualStateManager. Karen's prose is sweet as honey. I wish I could write like Karen!

Charles Petzold tagged me and challenged me to answer the following questions as part of a software development meme that's going around.

How old were you when you first started programming?
I had a couple of programming courses in college, but I didn’t really start programming until I got out of school and bought my first computer (a Commodore 64). I was 23 at the time.

How did you get started in programming?
Writing games for the Commodore 64. I tried to sell some of them, but was never successful.

What was your first language?
BASIC. I had a class in BASIC in college, I believe at the end of my freshman year.

What was the first real program you wrote?
As best I recall, a game for the Commodore 64. It was called “747” and was essentially a 2-dimensional version of Lunar Lander. I also wrote a version of it for the TI-59 calculator and got in a bit of trouble when scientists and engineers at Oak Ridge National Laboratory where I worked started playing it for hours at a time. For a short time, productivity at ORNL probably dropped 10%. :-)

What languages have you used since you started programming?
BASIC, FORTRAN, 6502/6510 assembler, 8086/8088 assembler, Pascal, C, C++, and C#.

What was your first professional programming gig?
Writing an accounting program for a local cable company. I did the work without a signed contract and wrote the whole thing (which mimicked the look of Lotus 1-2-3) in assembly language—in part because I wanted it to be lightning fast, and in part because I didn’t really know any high-level languages. I never got paid for the job. But I did learn that you couldn’t make a living turning out contract software using assembly language. That was about the time Turbo Pascal started making a splash, so I went out and bought a copy and spent the next couple of years writing lots of Pascal.

If you knew then what you know now, would you have started programming?
Absolutely. If I weren’t a programmer, I’d have to get a job.

If there is one thing you learned along the way that you would tell new developers, what would it be?
Be curious and inquisitive. Learn new stuff. I run into so many developers who are so beset with deadlines that they can’t—or don’t—take time to look up and see what’s happening in the world around them. For example, if you’re a Web developer right now, you should be learning about Silverlight. Lack of time isn’t an excuse. If you’re not playing with new technologies at night, then you’re a worker bee rather than a difference maker. Be passionate! If you can’t be passionate, then maybe you’re in the wrong line of work.

What's the most fun you've ever had ... programming?
Probably working a job a couple of years ago with Kenn Scribner. We had an impossible job to do with an impossible deadline and a team of two to do it. We worked crazy hours for two months building a cool site with ASP.NET and ASP.NET AJAX (then known as “Atlas”) and didn’t get the final functional requirements until a few hours before the go-live deadline. But it worked, and it had never even been tested against the production database it was designed to go against. When it comes to hard-core trench warfare, there’s no one I’d rather go into battle with than Kenn. Send the guy an e-mail at 2:00 a.m. and if you haven’t heard back by 2:01, his house is probably on fire.

A close second was writing DOS utilities for PC Magazine in the 1980s. I met some amazing people back then (Bill Machrone, Paul Somerson, Neil Rubenking, Charles Petzold, Phillipe Kahn, Steve Ballmer, and Bill Gates, to name a few) and really got a feel for what our industry was all about. I’d work all day as an engineer, then rush home and put on my programmer’s cap and work on my latest utility. As soon as I’d finish one, I’d start on the next, and PC Magazine would pay for as many as I could write. I paid off my first house that way. More importantly, I ultimately realized that I had more passion (and talent) as a programmer than as an engineer. Giving up engineering was the scariest thing that I ever did, but it was also the smartest.

So Who's Next?
I tag…Kenn Scribner!

Jeff Atwood wrote a great blog post about why Microsoft can't use open source in their products. Jon Galloway wrote a complementary post providing some specifics from a Microsoft insider explaining why Microsoft can't use open source. One of Jon's salient points is as follows:

Let's say Microsoft took my advice and shipped Paint.NET as a Windows Vista Ultimate Extra. Unbeknownst to Microsoft - or even the Paint.NET project leads - a project contributor had copied some GPL code and included it in a patch submission (either out of ignorance or as with malice aforethought). Two years later, a competitor runs a binary scan for GPL code and serves Microsoft with a lawsuit for copyright infringement. Microsoft is forced to pay eleventy bajillion dollars and damages. Perhaps even worse, they're hit with an injunction which prevents selling the offending application, which requires recalling shrinkwrapped boxes and working with computer vendors who've got the software pre-installed on computers in their inventory. All for shipping a simple paint program.

This "nightmare scenario," as Jon calls it, is more real than you might think. In my various roles as a Microsoft contractor and Wintellect cofounder, I have been involved, directly or indirectly, in a handful of lawsuits lodged against Microsoft over the years. And some of them have blown my mind. A few years ago, Wintellect took on the expert witness role when a gentleman sued Microsoft claiming that he invented Minesweeper and Microsoft stole it from him. The plaintiff wanted a royalty for every copy of Windows ever sold with Minesweeper! You can imagine how this went over with the brass at Microsoft.

Developers at Microsoft often joke that Microsoft has more attorneys than developers, or that "there's an attorney for every programmer." It's not quite true, but it sometimes seem as if it is. I personally know of three groups at Microsoft that wanted to use controls from the AJAX Control Toolkit in their projects and were told by Legal that they couldn't since the Toolkit is now open-source and contains code not written by Microsoft. Is Legal just being stodgy? Not given the long history of frivolous lawsuits filed against Microsoft by people hoping Microsoft will throw them some cash to go away. That's one attribute of Bill Gates that I've always admired: when he thinks he's right, he'd rather spend a million dollars defending his position than one dollar in hush money.

It would be nice if Microsoft could use open source. But given today's legal climate, there's no way that they--or any other company that sells software--can afford to.

You may have noticed that our blog was down for a couple of days last week. Lightning struck our server and our IT folks worked around the clock to get wintellect.com back online. Most of the site is back to normal now and we're working on the last 2% or so. A few blog entries were lost forever, including one I posted just before the storm detailing some recent updates to my downloadable Silverlight code samples. I wanted to post those again so everyone's aware that they're there.

A while back I published a Silverlight 1.0 page-turning framework in MSDN Magazine. Silverlight 2 Beta 2 exposed a bug in my code that has since been fixed. You can download a revised version of the source code here. If you used my framework to build page-turning apps of your own, simply replace the old copy of PageTurn.js with the new and you'll be good to go.

I have also updated SilverLife and my Silverlight interop demo for Beta 2. I'll be posting more updated samples this week.

I took Thursday and Friday of last week off and drove up to Winamac, IN for a jet event called Jets Over the Heartland. It's one of the most popular summertime RC jet meets and is held at one of the country's premier RC flying fields. The 800' x 50' runway can handle all but the very largest RC jets, and the surrounding terrain is flat and wide open. I did some flying of my own and spent a lot of time admiring the other jets, which included Lewis Patton's big beautiful F-18, Larry Kramer's hopped-up KingCat, Bob Violett's award-winning F-86 Sabre, and many more. I also came home with a new ride of my own:

Bob, Jeff, Dustin, and the Bandit 

That's Bob Violett, designer of the aircraft, on the left, and Dustin Buescher, who built the aircraft, on the right. Dustin taught me how to fly jets last year and continues to mentor me as I progress from jet rookie to jet pilot. Dustin is one of the best RC pilots I've ever seen and is a member of the U.S. national team that competed in the 2007 Jet World Masters last year in Ireland. The aircraft in the foregound is a BVM Bandit. The pitot tube sticking out of the nose is wired into the ECU (the unit that controls the turbine) to speed-limit the jet to 200 mph. Otherwise, the jet could fly so fast that sudden movements might rip the wings off. It's a kick to fly and maybe one day I'll be able to do 200 mph slow rolls 3 feet above the runway like Dustin. (Yeah, right!)

TechEd was split into two weeks this year--one for developers and one for IT folks (a formula that has worked well at TechEd Europe the last couple of years)--and Monday morning TechEd Developers begins with a slate of full-day pre-conference sessions. I'm doing a precon on Silverlight, so if you plan to be at TechEd, stop by and join the party! It's going to be fun. I have lots of slides to show, but more importantly, I have plenty of demos prepared. If you've heard about Silverlight but haven't yet had the opportunity to dive into it, Monday's precon is a great way to get started. We'll start at square one and build up until you've seen most of the features of Silverlight 2.

I'm doing breakout sessions Wednesday and Thursday on Silverlight, asynchronous ASP.NET programming, and ASP.NET AJAX. Hope to see you there!

I'm in Hyderabad, India preparing to work on the Microsoft campus this week and I feel like I'm in the movie "Groundhog Day." My luggage didn't make it with me. When this happened to me in Europe last year, I went for almost a week without my luggage. Each day I would call the airline and each day I was told that my luggage would arrive tomorrow. Yesterday KLM told me that my luggage would arrive today. Today KLM tells me it will arrive tomorrow. It's deja vu all over again.

The smart international traveler brings a few basic necessities in his carry-ons. I brought my toothbrush but not much else because I carried on my laptop and many countries are anal about limiting you to one carry-on (England and India being the worst). I bought a pair of shorts yesterday because it's over 100 degrees in Hyderabad right now. Since I've been wearing the same shirt since I left home Thursday afternoon, today I'll probably buy a shirt.

The trip over here wasn't without glitches, either. About an hour from Amsterdam, the passenger next to me knocked over a full glass of orange juice, soaking my pants and my seat. I dried off as best I could and let my body heat dry my pants. By the time I boarded the flight to Hyderabad, my pants had finally dried out. But shortly after take-off, the flight attendants served orange juice, and--you guessed it--the person sitting next to me knocked his over and soaked me again! I ended up changing seats and wearing a pair of sweat pants borrowed from the flight crew for the remainder of the flight.

So let's see...in the future, I need to bring at least one change of clothes for the airplane (preferably two, since there's no rule limiting you to one beverage spill), and at least one or two more to tide me over while I wait for my lost luggage to be delivered. But wait...some airlines won't let you bring that much baggage on board unless maybe you're willing to check your laptop and other electronic gear.

No wonder the airlines are going bankrupt.

To top it off, Vista is giving me fits again. I installed a Logitech Webcam on my wife's new Vista PC so we could do video calls while I'm in India. It worked fine for a day or two, but now something else fails each time we connect. Either the video doesn't work or the microphone doesn't work or something else goes wrong. I've had my wife download and install new drivers, so far without success. I don't know for a fact that the problem is Vista, but it's not much of a stretch to believe that the camera would be working fine on XP. I'll find out for sure when I get home.

And if I verify that the problem is Vista, I think I'll repave her PC and install XP until Microsoft can release an operating system that works with brand-name devices.

My latest Wicked Code column is now online at MSDN Magazine. Titled "Silverlight Page Turning Made Simple," it presents a Silverlight 1.0 framework for building slick page-turning applications. I mentioned the framework in an earlier blog post but didn't publish the source code because it needed to appear in MSDN Magazine first. Now you can download it, use it, and modify it to your heart's content.

And yes, I'll port the framework to Silverlight 2.0 soon.

I have largely avoided problems with Vista by only running it on PCs on which it comes preinstalled. At least I avoided problems until a few weeks ago. With a total of five PCs and laptops now running Vista in my house, the constant avalanche of automatic updates seems to break something every day. The latest issue I’m fighting is one that causes ASP.NET apps launched in IE 7 from Visual Studio 2008 to sometimes start with JavaScript disabled. It’s pretty hard to teach an ASP.NET class when LinkButtons don’t work.

But worse than having ASP.NET broken on my development box is what IE 7 has done to the PC in the kitchen. For more than 20 years my wife has used my hand-me-down PCs. Last week I bought her her first-ever new PC:  a Dell quad-core with 3 GB of RAM, a 500 MB hard disk, a 20-inch LCD monitor, and Vista Home Premium. (For the first time ever, I’m envious of her PC!) At first I was a little hot when Vista didn’t support my trusty USB wireless network adapter, but $70 and a new adapter later, Vista was happy and so was I.

The smiles didn’t last long. My wife fired up IE 7 on her new computer and went to our high school’s parent portal to check my son’s math grade. IE, however, wouldn’t let her get past the login page; it kept insisting “Internet Explorer cannot display the webpage.” She asked if this was another Vista problem. I knowingly assured her it wasn’t, and informed her that she had been running IE 7 on XP for a long time. Just to make sure, I downloaded the latest version of Firefox and went to the parent portal. Much to my surprise, Firefox let me log in and view grades just fine! I spent the next couple of hours toggling settings in IE 7 trying to get past the problem, and a couple of hours after that doing Web searches and analyzing HTTP traffic to find out why IE 7 couldn’t display a page that Firefox had no problem with. (It has something to do with “302 Temporarily Moved” responses coming back over SSL/TLS, but that’s as far as I’ve gotten with it.)

My wife can still check our son’s grades with IE 7 on her old XP PC. She can check grades with Firefox on her new Vista quad-core. But she can’t use IE 7 to check grades on Vista. She’s confused, and so am I.

A number of people have asked me in recent weeks whether two Silverlight 2 controls hosted in the same page can communicate with each other, and if so, how. I tell them they need to build a JavaScript bridge between the controls and then the controls can talk to each other just fine.

Tonight I built a sample app to demonstrate. Here's what it looks like:

Control Interop Demo 

You drag the red ball in the upper rectangle and the blue rectangle in the lower rectangle mirrors the red ball's moves. The interesting aspect of this application is that each rectangle represents a different Silverlight control instance. In other words, the page hosts two Silverlight controls, and the red ball lives in one control while the blue ball lives in the other.

Here are the OBJECT tags used to instantiate two Silverlight controls:

<div id="silverlightControlHost1">

  <object data="data:application/x-silverlight,"

    type="application/x-silverlight-2-b1" width="400"

    height="300" id="SourceControl">

    <param name="source" value="ClientBin/InteropDemo.xap"/>

    <param name="onerror" value="onSilverlightError" />

    <param name="background" value="white" />

  </object>

</div>

   

<div id="SilverlightControlHost2">

  <object data="data:application/x-silverlight,"

    type="application/x-silverlight-2-b1" width="400"

    height="300" id="TargetControl">

    <param name="source" value="ClientBin/OtherControl.xap"/>

    <param name="onerror" value="onSilverlightError" />

    <param name="background" value="white" />

  </object>

</div>

Each control has its own DIV, and each loads a different XAP file. How did I get Visual Studio to build two XAP files, each containing a separate control assembly? I just added a second Silverlight Application project to the solution. If you already have a Web project in the solution, Visual Studio asks if you want the new project linked to the existing Web project:

Add Project Dialog

Visual Studio obligingly adds the Silverlight project to the solution and configures the build settings so that building the project creates a second XAP file that, like the XAP file from the first project, is copied into the Web site's ClientBin directory.

To link the two Silverlight controls together, I began by converting the code-behind class for the second control (the one containing the blue ball) into a scriptable class and adding a scriptable method named MoveBall:

[ScriptableType]

public partial class Page : UserControl

{

    public Page()

    {

        InitializeComponent();

        HtmlPage.RegisterScriptableObject("other", this);

    }

 

    [ScriptableMember]

    public void MoveBall(double x, double y)

    {

        Ball.SetValue(Canvas.LeftProperty, x);

        Ball.SetValue(Canvas.TopProperty, y);

    }

}

Then I added the following JavaScript function (the "bridge") to the HTML page:

var _target = null;

   

function moveBall(x, y)

{

    if (_target == null)

        _target = document.getElementById('TargetControl');

    _target.content.other.MoveBall(x, y);           

}

Finally, I added the following statement to the MouseMove handler in the first control (the one with the red ball):

HtmlPage.Window.Invoke("moveBall", x, y);

The X and Y coordinates passed in represent the current position of the red ball--the position I just moved it to in response to the latest mouse move.

See how it works? You move the red ball. The MouseMove handler that moves the ball also calls the JavaScript moveBall function, which in turn calls the second control's MoveBall method. The red ball moves and the blue ball moves, too. This sample takes advantage of Silverlight 2's rich DOM integration features which allow C# methods to call JavaScript functions, JavaScript functions to call C# methods, and a whole lot more.

I'll post the source code this weekend. For now, it has been a long week, it's late, and I'll be locked away in a hotel all weekend building slides for my Silverlight precon at TechEd and taking care of other jobs that have piled up in my to-do list. Time to get some sleep.

UPDATE: The source code has been posted and you can download it here. In addition, I posted a new version of SilverLife that uses DispatcherTimer rather a Storyboard to drive cell animations. You can download the new version here.

I was having dinner with Walt Ritscher tonight when he posed an interesting question: how can a Silverlight app load its own XAML from an application assembly?

I thought I knew the answer, because I had just finished doing a lot of research into the various ways to package code and resources in Silverlight 2.0. And I knew that the XAML files in a Silverlight 2.0 app get embedded as resources in the application assembly, which in turn gets embedded in the application package (the application's XAP file). But when I got back to my hotel and tried it, it didn't work. So I played around some and found the secret incantation.

Here's the Page.xaml file in the test app that I wrote:

<UserControl x:Class="SilverlightTestApp.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock x:Name="Output" />

    </Grid>

</UserControl>

And here's the output from the program:

XAML Output 

Finally, here's the code in Page.xaml.cs that produces the output by loading Page.xaml from the application assembly and assigning it to a TextBlock object:

StreamResourceInfo sri = Application.GetResourceStream

    (new Uri("SilverlightTestApp;component/Page.xaml", UriKind.Relative));

StreamReader reader = new StreamReader(sri.Stream);

Output.Text = reader.ReadToEnd();

The trick is to include "assemblyname;component" in the URI passed to GetResourceStream, even though the assembly you're loading from is the application assembly and not a library assembly. Normally you don't have to include the assembly name if you're targeting the application assembly, but this is obviously an exception--at least in Beta 1.

I don't know how useful this information is, but it ought to make a good icebreaker at a Silverlight party.

Like a lot of folks, I was pretty impressed the first time I saw Silverlight 2.0's new Deep Zoom feature at work. So I downloaded Deep Zoom Composer and starting building apps to see what makes Deep Zoom tick. Deep Zoom Composer is cool, but what really makes Deep Zoom shine is the MultiScaleImage control. It is amazing how much you can do with so little code.

I built an app that incorporates some of my favorite travel photos:

Deep Zoom

You can zoom in and out with the mousewheel or pan around by dragging with the left mouse button down. Some of the photos I used are higher-res than others, but in most of them you can zoom in enough to reveal quite a lot of detail.

You can view the app online, and you can download the source code. The download doesn't include the images because the images comprise more than 30 MB. But you can generate your own images and metadata with Deep Zoom Composer and plug them into my demo. All you have to do is copy the output folder created by Composer into DeepZoom_Web's ClientBin folder and point the MultiScaleImage control declared in Page.xaml to the info.bin or items.bin file in the output folder. Then fire up the app and zoom away.

When I exported from Deep Zoom Composer, I checked the "Create Collection" box to export a collection of images rather than one monolithic image. Although my code currently doesn't take advantage of it, exporting a collection allows you to use the SubImages property of the MultiScaleImage control to addess the individual images and even to change their position, aspect ratio, opacity, and Z-index. It appears (though I haven't tried it yet) that you can also change the zoom factor of individual images. Look for an updated demo in the near future that demonstrates some of these enticing capabilities.

Quick: can you spot what's wrong with this code?

Thread thread = new Thread(new ThreadStart(RunClock));

thread.Start();

  ...

private void RunClock()

{

    while (true)

    {

        Clock.Text = DateTime.Now.ToLongTimeString();

    }

} 

The intent is to launch a thread and have that thread run an infinite loop updating a XAML TextBlock object that shows the current time of day. Aside from the questionable design (there are much more efficient ways to keep a time-of-day display up to date), there's something seriously wrong with this code. In fact, if you run it you'll find that the time-of-day display never updates at all. And therein lies a story.

I was surprised last year when I saw that the Silverlight 1.1 alpha had a System.Threading namespace complete with all the classes I needed to launch threads, synchronize threads, acquire threads from a thread pool, etc. Silverlight 2.0 Beta 1 contains all these classes and more. I'm still amazed that I can write multithreaded apps that run in a browser, and I've been doing a lot of that lately--not because I need to, but just because I can. Silverlight 2.0's BackgroundWorker class simplifies the process of running tasks on background threads, and DispatchTimer is a handy alternative to empty Storyboards for programmable game timers. But you don't have to use either of them; you can use Thread.Start, ThreadPool.QueueUserWorkItem, asynchronous delegates, and other mechanisms familiar to .NET developers to relegate tasks to background threads.

There is one nuance to Silverlight threading that you should be aware of, however: controls and other XAML objects can only be updated by the UI thread (the main thread that drives a Silverlight app). The reason the attempt to set the TextBlock's Text property in the example above fails is that we're attempting to set it from a background thread. For the sample to work, you need to modify it as follows:

private delegate void UpdateUIDelegate();

  ...

Thread thread = new Thread(new ThreadStart(RunClock));

thread.Start();

  ...

private void RunClock()

{

    UpdateUIDelegate action = new UpdateUIDelegate(UpdateUI));

 

    while (true)

    {

        Clock.Dispatcher.BeginInvoke(action);

    }

}

 

private void UpdateUI()

{

    Clock.Text = DateTime.Now.ToLongTimeString();

}

In the corrected code, the background thread marshals the call back to the UI thread by calling UpdateUI through a delegate invoked via the TextBlock object's Dispatcher property. Dispatcher is inherited from DependencyObject and is therefore present in all UI objects. For old folks like me who used to program Windows, this is analagous to using PostMessage to post a message to another thread. You don't have to use the Dispatcher property of the object you intend to update; you can use Dispatcher on any UI object to marshal the call to the UI thread.

Programmers who have written multithreaded WPF apps won't be surprised by any of this because WPF also requires UI objects to be updated by UI threads. And of course there are ways to avoid using Dispatcher altogether. The BackgroundWorker class, for example, fires events on UI threads, so there's no need to do any marshaling before updating a UI object. But there are times in Silverlight when you simply can't avoid marshaling from a background thread to a UI thread, and when those circumstances arise, it's useful to know about Dispatcher.

A few weeks ago I posted a short code sample demonstrating how to do mousewheel zooms in Silverlight 1.1. They're easier to do in Silverlight 2.0 and can be done without calling out of managed code, thanks to the new HtmlWindow class (and the HtmlPage.Window property, which returns a reference to an HtmlWindow).

Here's a summary. First, assume you have a ScaleTransform that facilitates zooms:

<ScaleTransform x:Name="ZoomTransform" />

Next, when the page loads, use HtmlWindow.AttachEvent to register a managed handler for mousewheel events:

HtmlPage.Window.AttachEvent("DOMMouseScroll", OnMouseWheelTurned);

HtmlPage.Window.AttachEvent("onmousewheel", OnMouseWheelTurned);

HtmlPage.Document.AttachEvent("onmousewheel", OnMouseWheelTurned);

Here's the event handler that responds to mousewheel events by manipulating the ScaleTransform:

private void OnMouseWheelTurned(Object sender, HtmlEventArgs args)

{

    double delta = 0;

    ScriptObject e = args.EventObject;

 

    if (e.GetProperty("wheelDelta") != null) // IE and Opera

    {

        delta = ((double)e.GetProperty("wheelDelta"));

        if (HtmlPage.Window.GetProperty("opera") != null)

            delta = -delta;

    }

    else if (e.GetProperty("detail") != null) // Mozilla and Safari

    {

        delta = -((double)e.GetProperty("detail"));

    }

 

    if (delta > 0)

    {

        // Zoom in

        ZoomTransform.ScaleX += 0.1;

        ZoomTransform.ScaleY += 0.1;

    }

    else if (delta < 0)

    {

        // Zoom out

        ZoomTransform.ScaleX -= 0.1;

        ZoomTransform.ScaleY -= 0.1;

    }

 

    if (delta != 0)

    {

        args.PreventDefault();

        e.SetProperty("returnValue", false);

    }

}

Anything affected by the ScaleTransform will now scale up and down with mousewheel movements.

My mousewheel event handler is browser-independent and correctly reports the direction of travel, but it doesn't take into account the differences in the magnitude of travel reported by various browsers. Scott Hanselman pointed me to an excellent blog post by Pete Blois that includes downloadable source code for a MouseWheelHelper class that accounts for differences in magnitude, too. Check it out if you want to make mousewheel handling simple as pie in Silverlight 2.0.

Silverlight 1.1 lacked a managed equivalent of JavaScript's window.alert, so when I wanted to pop up a message box (actually, an alert box) in Silverlight 1.1, I used the platform's DOM integration features to fire a scriptable event from C# and handle the event in JavaScript. Then, in the event handler, I called window.alert.

There's no need for such shenanigans in Silverlight 2.0 because you can call window.alert via a managed wrapper:

HtmlPage.Window.Alert("Error!");

HtmlPage.Window contains a reference to an HtmlWindow object representing the browser window. You can also use HtmlWindow.AttachEvent to register managed handlers for mousewheel events, making it relatively easy to process mousewheel events in Silverlight 2.0 without the intervention of JavaScript. I'll provide an example in a future blog post.

More Posts Next page »