Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

May 2007 - Posts

Old iPaq and Media Player 11?

This is so frustrating I thought I'd just make a blog post and see if someone has a solution. I have an old HP iPaq of the 1900 series, partnered with my Vista Laptop. I like that old PocketPC because it's fairly slim, easy to program and runs a few nice emulators like the ScummVM (mmmh, Sam & Max...). Anyways, every single freaking time I launch Media Player on the laptop, if the iPaq is docked, I'm getting a dialog box that says "your device is using an outdated driver that is no longer supported by Windows Media Player. For additional assistance, click Web Help." No "don't show this again" checkbox, you have to endure the dialog every single f*#$% time.

So I click Web Help, and end up on this (not) very helpful page:
http://www.microsoft.com/windows/windowsmedia/player/webhelp/default.aspx?&mpver=11.0.6000.6324&id=C00D118E&contextid=232&originalid=C00D118E
which explains that their only solution to my their problem is to "roll back to Media Player 10". Uh? On Vista? Nice.

I DON'T EVEN WANT TO SYNCHRONIZE MY MEDIA WITH THIS DEVICE! It's way too small anyways, and I never said that's one of the things I wanted to sync. Why do we have a new Sync Center and there's no option in there to turn that off? Why doesn't it appear in the sync part of Media Player?

Anyway, did anyone experience that and found a way to turn it off? Please?

UPDATE: I just found this thread, which leaves little hope of fixing this... http://www.microsoft.com/windows/windowsmedia/community/newsgroups/WindowsMedia/default.mspx?dg=microsoft.public.windowsmedia.player&mid=2b1aa191-83d8-4f20-8756-dde7695bfdef&sloc=en-us

Surface computing is here

Just amazing. I had seen this at internal Microsoft events and knew that something was cooking, but it's almost here. Not just a cool tech demo anymore but something that launches this winter and can already be used at the New-York Sheraton.

http://www.microsoft.com/surface/

(through http://msmvps.com/blogs/luisabreu)

Microsoft Ajax events - part 2: exposing events from custom classes

 

In part 1, I showed how to subscribe to events exposed by JavaScript classes built on Microsoft Ajax. In this post, I'll show how to expose new events from your own classes.

Theoretically, the only things you have to do to expose an event are to implement "add_myEvent" and "remove_myEvent" methods that add or remove handlers, and to call all subscribers when relevant. In practice, managing the list of handlers for each event is really boilerplate code that you would have to reproduce for every event. This is why the Sys.Component base class exposes an events property that is an instance of Sys.EventHandlerList, which makes the event handler management a lot easier, and also has a few performance advantages. This is not a new pattern, System.Web.UI.Control also has an Events property of type System.ComponentModel.EventHandlerList, so if you know the .NET pattern you should feel right at home.

Let's look at a very simple example for which we'll build a very simple timer component. Our timer will expose a single event: tick (in addition to the events the base class supports, but we'll get back to that in a moment). The code for the add and remove event accessors is really simple, and this is all you have to do to expose any event:

add_tick: function(handler) {
    this.get_events().addHandler("tick", handler);
},
remove_tick: function(handler) {
    this.get_events().removeHandler("tick", handler);
},

The only thing that will vary in this code is the event name ("tick" here).

Calling subscribers is done from the _tick private function of our Timer class:

_tick: function() {
    var handler = this.get_events().getHandler("tick");
    if (handler) handler(this, Sys.EventArgs.Empty);
    // [...]
}

What's important in this method is how the _tick function gets a unique function reference for the "tick" event that will forward the calls to all subscribers. This makes Ajax events similar to .NET's multicast events. The function reference that getHandler returns can be null (in the case there are no subscribers) so it's important to test it before using it, but calling it is as simple as calling a regular function: the multicasting is entirely and internally handled by Sys.EventHandlerList.

Note that this _tick function is wired using window.setTimeout from the start method as can be seen in the full source code. I also omitted the code that rewires the timeout for the next tick.

It should be noted that the signature for the handlers is always (sender, arguments) where arguments are an instance of a class derived from Sys.EventArgs. Here, there's really no relevant information that we want to send to the handlers, so we're just using Sys.EventArgs.Empty, which is a special, empty instance of Sys.EventArgs.

For your own events, you can build your own class that derives from Sys.EventArgs. You should clearly document that this new class works with your event. Typically, the new argument class should take a constructor parameter for each of the pieces of information you want to transmit to the handlers. There should also be a property getter for each of those, but there usually won't be a setter. The reason is that these arguments should most of the time be considered immutable. There are a few cases though when this is not true and the handlers should be able to communicate back to the event publisher. One example of that is cancellable events (see Sys.CancelEventArgs and its cancel property). What's important in those case is that handlers should never rely on the values of those mutable properties. Only the event publisher can do anything depending on them. In the cancellable case, for example, what setting cancel to true does is prevent an action that would have happened *after* all the handlers have been called, but it doesn't prevent the remaining handlers from being called.

In the case of the Timer component, the event is raised by an externally happening source (the timeout feature exposed by JavaScript), which is why _tick is a private function. In some cases, it may be desirable to make it possible for public consumers of the class to raise the event. In this case, the convention is to expose a public method named "raise[event name]". For example, the base Sys.Component class exposes a raisePropertyChanged method that is typically called by derived classes to raise the propertyChanged event from the setters of properties that wish to advertise their changes.

Most of the time though, the event will be raised as part of a larger operation, which is what's being exposed publicly, and there's no point in having a "raise..." method. Once more, an example of that can be found in Sys.Component: dispose raises the disposing event before it actually does its cleanup work.

This pretty much covers what you need to know to implement your own custom events. In the next and final post in this series, I'll show how to integrate Microsoft Ajax events with the OpenAjax hub.

Full code for the timer component:
Timer.js.txt (rename to Timer.js before using that file)

A sample page that uses the component:
Clock.aspx.txt (rename to Clock.aspx and include in a Microsoft Ajax site with Timer.js to use)

Read part 1 of this post:
Microsoft Ajax events - part 1 - subscribing

The Wiimote doesn't work...

... for anything else than aiming and frantically moving up and down. In other words, slow movements aimed at the screen work well, as do fast, imprecise movements, but anything else is impractical.

But let's move back a little: why am I saying that? Well, it's been a few months since I've bought the Wii. I admit I was skeptical of the Wii-remote at first but revised my judgement once I tried the system at a few friends' houses. I've been a loyal Nintendo customer for years: I've owned every portable system from the first GameBoy to the DS light, as well as a few of their regular consoles. I don't even know how many versions of Mario Kart I've bought. The reason I'm saying all that is to assure you that I'm not partial *against* Nintendo. Call it tough love if you want. Anyways.

I've owned the Wii for a few months now and I've really tried hard to love it. And I do most of the time. What really sold me the console was the Golf part of Wii Sports. Even though the game is incredibly shallow (only nine holes and 3 clubs), it promised a lot. For the first time, a video game system seemed to allow for the possiblity of a golf simulator. Not just a game, but something that feels and operates like the real thing. Wii Sports isn't quite there though: slice and hook are determined randomly if you hit the ball too hard, and it doesn't really follow your moves but really is based only on timing (do any movement in any direction at the right speed and it will just work the same, as my 3-years-old daughter quickly dicovered). But it definitely felt like the potential was immense. So I got up at 5 in the morning and waited in front of Target in the cold hours of a Sunday morning to get the system.

The first golf game I tried was a very bitter disappointment: Super Swing Golf has an absolutely incomprehensible control scheme. You actually need to press a button at the top of your swing. Why, why, why would they break the game like this? Shouldn't the remote just detect that you stopped going up and started going down? At the time I just blamed Tecmo and thought I would just wait for Tiger Woods. I was pretty confident that if someone could get it right, it would be EA. Unfortunately, I later understood that Tecmo wasn't to blame for the clunky controls. The wiimote was.

When I finally got my hands on Tiger Woods, at first everything just seemed peachy. I was (completely) missing a lot of shots but I thought it was just me learning the game. So I tried and tried, and as I gained experience it became very clear that the number of missed shots was not going down. It also became very clear what was responsible for them. The shot would just go before I was done lifting the remote. The wiimote seems to be incapable of reliably detecting the change of direction. The fact that it points away from the the sensor bar at that moment probably doesn't help. In any case it pretty much explains why Tecmo felt you had to press a button to tell the system you were done raising your arm.

The putting has similar issues, again because the remote isn't directed at the sensor bar. The club doesn't move with the remote. It just starts to move as soon as you press B. Like in Wii Sports, it's really only based on timing, not on the way you move.

Finally, to slice or hook, you need to add a different move to the end of your swing, which is untirely unnatural and doesn't exist in real golf where these effects are caused by the angle with which you hit the ball. But of course the wiimote can't detect such subtle movements in the middle of a fast trajectory such as a swing.

It should be clear by now that there is a whole class of moves that the wiimote is very bad at detecting. The problem is that those are the ones that are necessary for most sports simulations, a type of game the Wii looked the most promising for. I'm really afraid that there will never be a good golf (and maybe tennis) simulation on this system.

The Wii remote definitely works for aiming at the screen (but a mouse would be much more efficient). It also works for frantic, imprecise movements. That's why Rayman Raving Rabbids works so well. Wii developers will have to work around those constraints one way or another and I'm pretty confident that this industry has enough smart people to figure out how to exploit the system for what works and carefully avoid what doesn't. We'll see great (non-mini) games for the Wii after a while, just like we did for the DS. I just doubt golf can be one of those...

Microsoft Ajax events - part 1: subscribing

When building Ajax applications, you basically deal with two kinds of events. First, there are DOM events, and second, events from JavaScript objects. This second category is not part of the EcmaScript specs (or of the DOM specs, of course) so each framework needs to define its own pattern to expose events. This makes it more difficult for developers to include components built on different frameworks into a single page, which is one of the problems that OpenAjax tries to solve. I'll get back to this in a future post and show how to integrate Microsoft Ajax events in the OpenAjax hub.

As with other parts of the Microsoft Ajax framework, we've tried to adhere to the .NET patterns as much as possible when we designed events in Microsoft Ajax. Events are defined by their "add" and "remove" accessors, which respectively add and remove handlers. For instance, PageRequestManager exposes a "beginRequest" event by exposing the "add_beginRequest" and "remove_beginRequest" methods. Both add and remove accessors have the same signature, which is that they take a single "handler" parameter of type Function.

So handling an event is twofold. First, you must subscribe to an event, which is as simple as the following highlighted code:

<%@ Page Language="C#" %>

<!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 runat="server"> <title>Untitled Page</title> <script type="text/javascript"> function pageLoad() { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (!prm.get_isInAsyncPostBack()) { prm.add_beginRequest(onBeginRequest); } } function pageUnload() { Sys.WebForms.PageRequestManager.getInstance()
.remove_beginRequest(onBeginRequest); } function onBeginRequest(sender, args) { Sys.Debug.trace(args.get_postBackElement().value +
" triggered a postback."); } </script> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager runat="server" ID="SM1"></asp:ScriptManager> <asp:UpdatePanel runat="server" ID="UP1"> <ContentTemplate> <asp:Button runat="server" ID="Button1" Text="Button 1" /> <asp:Button runat="server" ID="Button2" Text="Button 2" /> <asp:Button runat="server" ID="Button3" Text="Button 3" /> </ContentTemplate> </asp:UpdatePanel> <textarea id="TraceConsole" cols="40" rows="15"></textarea> </div> </form> </body> </html>

This page starts by subscribing to the beginRequest event of the page request manager. The handler for the event which is passed to add_beginRequest, onBeginRequest, looks at the event arguments and displays the value of the button that triggered the postback in the trace console. This brings us to the second half of using events, writing the handler. All Microsoft Ajax event handlers, by convention, and exactly like in .NET, have a similar signature: they take two parameters, the event sender and the event arguments. The sender is the object that raised the event (in the example above, that would be the PageRequestManager) and the arguments are an instance of a type that derives from Sys.EventArgs. Many events will be associated with a specific argument class to enable the handler to get additional and specific information about the event. In the example above, we're using the postBackElement property of the arguments, which are of type Sys.WebForms.BeginRequestEventArgs. Similarly, the propertyChanged event on Sys.Component is associated with Sys.PropertyChangedEventArgs, which exposes a propertyName property that enables the handler to determine the name of the property that triggered the event. In other words, to learn how to properly handle an event, start by exploring its associated arguments class.

In the next post, I'll show how to expose a custom event from your own classes:
http://weblogs.asp.net/bleroy/archive/2007/05/22/microsoft-ajax-events-part-2-exposing-events-from-custom-classes.aspx

More Posts