Silverlight 5 provides multi-window support for Out-of-Browser (OOB) applications with elevated trust. Unfortunately the ContextMenu provided in the December 2011 release of the Silverlight Toolkit is not multi-window aware which means that context menu’s opened from secondary windows only appear in the main window.
There are bugs open on MS Connect and a work item on the Toolkit’s issue tracker, but if in the meantime like me you can’t wait for it to be fixed, you can follow the steps below.
Note: this is also an issue in the current release of Telerik’s Silverlight RadControls.
Finding the code
First off you’ll need to get the source code for the Silverlight 5 Toolkit which somewhat surprisingly is not available through the Source tab on the CodePlex site. Instead you can download and install the Silverlight 5 Toolkit - December 2011 release MSI. Then locate the source code distributed in a zip file:
%Program Files%\Microsoft SDKs\Silverlight\v5.0\Toolkit\dec11\Source\Source code.zip
The context menu code is part of the Controls.Input.Toolkit project of the Controls.Toolkit solution.
Underlying issue
Underneath the Silverlight 5 Toolkit’s ContextMenu class uses the Silverlight Popup class to display content on top of existing Silverlight content. In Silverlight 5 the Popup class has a new method SetWindow to set the window it pops up in, however it is not being called.
Fixing the code
To fix the code we’ll also need to discover the window that the user has clicked in using the Window.GetWindow static method.
1) Add a _currentWindow field to the ContextMenu class:
/// <summary>
/// Stores a reference to the current window.
/// </summary>
private Window _currentWindow;
2) Set the _currentWindow value in the HandleOwnerMouseRightButtonDown method:
void HandleOwnerMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is DependencyObject)
{
_currentWindow = Window.GetWindow(e.OriginalSource as DependencyObject);
_rootVisual = _currentWindow.Content;
}
OpenPopup(e.GetPosition(null));
e.Handled = true;
}
2) Call the Popup’s SetWindow method in the OpenPopup method:
_popup = new Popup { Child = _overlay };
_popup.SetWindow(_currentWindow);
Get it now
The source is available on CodePlex: Silverlight Multi-Window Controls
It’s a bit of a long story. A chain of events would unfurl that would lead me inextricably to writing a clone of a 70s video game. It started a few weeks ago while exploring early 90s dance tracks on Spotify, when I happened upon the seminal EP - Clonks Coming by the Sweet Exorcist. Later a lack of content on Spotify would push me towards YouTube and to find a hypnotic collage of Space Invaders, Beach Balls, Pong and the BBC test card girl.
Tapping along to the retro beeps on the train to London, a couple of white rectangles started moving up and down with the keyboard and a small white square began floating diagonally, and then the train reached King’s Cross. Much later a copy of RetroActivity would arrive in the post and I would return to the rectangles and make the white square bounce. Well, not before I had spent a few hours playing with Rebirth. The code is posted as an F# Snippet and fits happily in just under 100 lines. You can play in the browser if you have the Silverlight plug-in installed, just click inside to start the game.
Player 1 keys 'Q' - up, 'A' - down. Player 2 keys 'P' - up, 'L' – down.
Today I added a few beeps and a score, and put the project up on BitBucket. I started out trying the new SoundEffect classs in Silverlight 5 that promises low latency sound but unfortunately it seems a bit temperamental and I had to switch to using the old MediaElement class.
There’s a couple of reusable routines that are specific to gaming, the first is to know what keys are pressed at any instant in time:
type Keys (control:Control) =
let mutable keysDown = Set.empty
do control.KeyDown.Add (fun e -> keysDown <- keysDown.Add e.Key)
do control.KeyUp.Add (fun e -> keysDown <- keysDown.Remove e.Key)
member keys.IsKeyDown key = keysDown.Contains key
The second is to synchronize the game updates with Silverlight’s rendering:
let run rate update =
let rate = TimeSpan.FromSeconds(rate)
let lastUpdate = ref DateTime.Now
let residual = ref (TimeSpan())
CompositionTarget.Rendering.Subscribe (fun _ ->
let now = DateTime.Now
residual := !residual + (now - !lastUpdate)
while !residual > rate do
update(); residual := !residual - rate
lastUpdate := now
)
If you’re interested in playing and making simple games, or even just coding, why not pop down to Skills Matter in London this Thursday for a PacMan Kata.
The F#unctional Londoners Meetup Group will be starting 2012 with a code Kata on Thursday January 26th at 6:30pm at Skills Matter.
Kata
The term Kata comes from martial arts. A code Kata is a short programming exercise for practicing an aspect of software development.
Back in November in the Programming with the Stars session at the Progressive F# Tutorials our celebrities Mark Needham and Mark Seemann took on the Tennis Kata, first in C# and then F#.
As the two Mark’s talked through their solutions a number of people worked on their own versions, 2 of which you can see on the F# Snippets site:
PacMan
Scanning over the Kata catalogue for ideas the PacMan Kata bit me immediately. Pacman finds himself in a grid filled with monsters. Will he be able to eat all the dots on the board before the monsters eat him?
To get things started I’ve built up a maze and some graphics. You can see an example over on F# Snippets that runs in the browser on http://tryfsharp.org which uses Silverlight: PacMan Maze
I’ve also created a repository on BitBucket with sample projects for Visual Studio 2010 targeting WPF, Silverlight and HTML/JavaScript.
The Javascript version uses the Pit compiler, you can see it running here. (Keys Q/A/Z/X *only in IE)
Look forward to seeing you at the event.