There are two very distinct ways to program on Windows Phone 7.x: Silverlight & XNA. Silverlight is about UI, retained graphics and is event driven. XNA is about immediate mode graphics, based on a timer and polling; Very different models indeed. Each has its strengths and weaknesses. One of the new features in WP7.1 (“mango”) is the ability to combine the two to get the best of both worlds.
Here’s a typical scenario where this need may come up: suppose you’re developing an XNA game (2D or 3D). In a typical game you need to allow some configuration, such as setting volume, level of play or simply showing a high score table. XNA is not built for that. Although you could some up with your own controls such as buttons, list, etc. implemented in XNA, that would be a lot of work, and might not look like the “native” Silverlight counterparts. If you could combine a Silverlight page with some controls and some XNA content – you would have a nice solution to the problem.
Here’s how to do that. First, we’ll start with a project template that is part of the latest Mango tools for Visual Studio 2010 called “Silverlight and XNA Application”:

This template sets up some tedious boilerplate code for things to start actually working. The main project has two pages: the first, MainPage.xaml is a Silverlight only page. It just hosts a single button that causes navigation to the other page, GamePage.xaml. Since the main page is not useful for our purposes, I’ll remove it and set the start page to be GamePage.xaml in WMAppManifest.xml:
- <Tasks>
- <DefaultTaskName ="_default" NavigationPage="GamePage.xaml"/>
- </Tasks>
Next, we want to create some Silverlight UI that should function correctly along with some XNA content. This is what I added in GamePage.xaml:
- <Grid LayoutUpdated="Grid_LayoutUpdated" x:Name="_mainGrid">
- <Grid.RowDefinitions>
- <RowDefinition />
- <RowDefinition Height="Auto" />
- </Grid.RowDefinitions>
- <Rectangle x:Name="_rect" Stroke="Transparent" Fill="Transparent" />
- <StackPanel Grid.Row="1" Orientation="Horizontal" Background="Black">
- <Button Content="Reset" Click="OnReset"/>
- <TextBlock Text="Balls:" Margin="10,0,0,0" VerticalAlignment="Center" />
- <Slider Value="1" Minimum="1" Maximum="30" Width="280" Margin="10,0,0,0"
- ValueChanged="OnChangeBalls"/>
- </StackPanel>
- </Grid>
Disregard the event handlers for now. This is how it looks in the designer:

Let’s try running the application as it stands. The result (in the emulator) is pretty disappointing:

The UI we just created is nowhere to be found. In actuality, it’s all there. I can even press the button if I can guess where it is. The problem is that XNA “takes over” and draws itself on top of everything, including the Silverlight generated UI.
How do we deal with that? I just want the XNA part to be above the controls I’ve placed. For this, we have to render the Silverlight UI into a texture, and then render that texture with the XNA scene, just like any other texture.
The key class here is UIElementRenderer. We’ll add a reference of that type to the GamePage class and create one in the LayoutUpdated event of the page:
- private void Grid_LayoutUpdated(object sender, EventArgs e) {
- if(_uiRenderer == null)
- _uiRenderer = new UIElementRenderer(_mainGrid, (int)_mainGrid.ActualWidth, (int)_mainGrid.ActualHeight);
- }
This UIElementRenderer can render the supplied element (via its Render method) (the main Grid in our example) into a texture. Then, we can render the texture like any other in XNA using a SpriteBatch – all this in the OnDraw supplied method, called each and every frame:
- private void OnDraw(object sender, GameTimerEventArgs e) {
- SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.LightBlue);
-
- _uiRenderer.Render();
- spriteBatch.Begin();
- spriteBatch.Draw(_uiRenderer.Texture, new Vector2(0, 0), Color.White);
- spriteBatch.End();
- }
Note that we don’t actually need to create that texture. It’s created internally by the UIElementRenderer. If we run the app now, we should see the Silverlight UI on top of the light blue background:

Now that the hard part is out of the way, let’s add some interesting XNA content to be rendered within the area reserved for it.
I’ve added a colored “ball” texture, created a Texture2D field to hold it, and load it in the OnNavigatedTo override (if it hasn’t been loaded already):
- protected override void OnNavigatedTo(NavigationEventArgs e) {
- // Set the sharing mode of the graphics device to turn on XNA rendering
- SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
-
- // Create a new SpriteBatch, which can be used to draw textures.
- spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
- if(_ballTexture == null)
- _ballTexture = contentManager.Load<Texture2D>("colorwheel");
-
- // Start the timer
- timer.Start();
-
- base.OnNavigatedTo(e);
- }
I’ve created a simple class to hold some state of a ball object. I’d like to create several of those, and move them around the light blue area. Here’s the simple Ball class:
- public class Ball {
- public Vector2 Speed { get; set; }
- public Vector2 Position { get; set; }
- public float RotationAngle { get; set; }
- public float RotationSpeed { get; set; }
- }
Every ball has its own position, speed, rotation angle and rotation speed (around its own axis). Now let’s add a List<Ball> field (_balls) to hold those, create one when the page is loaded and add or remove balls whenever the slider’s value change:
First, a general method to create a new, randomized ball:
- Ball CreateNewBall() {
- var ball = new Ball {
- Position = new Vector2(_rnd.Next((int)_rect.ActualWidth - _ballTexture.Width / 2), _rnd.Next((int)_rect.ActualHeight - _ballTexture.Height / 2)),
- Speed = new Vector2((float)_rnd.NextDouble() * 8 - 4, (float)_rnd.NextDouble() * 8 - 4),
- RotationAngle = (float)_rnd.NextDouble() * 360,
- RotationSpeed = (float)_rnd.NextDouble() * 1.5f - .75f
- };
- return ball;
- }
_rnd is a Random instance, created at construction time, and _rect is a transparent Rectangle that is stretched to the first row of our grid (where the XNA content resides).
When the page is loaded, create a single ball (in the GamePage constructor):
- Loaded += delegate {
- _balls.Add(CreateNewBall());
- };
Whenever the slider value changes, we’ll update the number of balls (in the _balls object):
- private void OnChangeBalls(object sender, RoutedPropertyChangedEventArgs<double> e) {
- if(_rect == null) return;
- int value = (int)e.NewValue;
-
- if(value < _balls.Count)
- _balls.RemoveRange(value, _balls.Count - value);
- else {
- int count = _balls.Count;
- for(int i = 0; i < value - count; i++)
- _balls.Add(CreateNewBall());
- }
- }
Now we need to update the balls position (and speed, if a ball hits the boundaries of the “game field”). This is done in the OnUpdate method, supplied by the project template (similar to a classic XNA Update method). I’ve also added some code that allows the user to touch a ball and swirl it to some direction based on finger drag:
- private void OnUpdate(object sender, GameTimerEventArgs e) {
- if(TouchPanel.IsGestureAvailable) {
- var sample = TouchPanel.ReadGesture();
- foreach(var ball in _balls) {
- if(Math.Abs(sample.Position.X - ball.Position.X) < _ballTexture.Width / 2
- && Math.Abs(sample.Position.Y - ball.Position.Y) < _ballTexture.Height / 2) {
- // found ball
- ball.Speed = new Vector2(Math.Min(25, sample.Delta.X), Math.Min(25, sample.Delta.Y));
- break;
- }
- }
- }
-
- foreach(var ball in _balls) {
- // update ball position
- Vector2 pos = ball.Position + ball.Speed;
- if(pos.X < _ballTexture.Width / 2) {
- pos.X = _ballTexture.Width / 2;
- ball.Speed = new Vector2(-ball.Speed.X, ball.Speed.Y);
- }
- else if(pos.X > (float)_rect.ActualWidth - _ballTexture.Width / 2) {
- pos.X = (float)_rect.ActualWidth - _ballTexture.Width / 2;
- ball.Speed = new Vector2(-ball.Speed.X, ball.Speed.Y);
- }
- else
- pos.X += ball.Speed.X;
-
- if(pos.Y < _ballTexture.Height / 2) {
- pos.Y = _ballTexture.Height / 2;
- ball.Speed = new Vector2(ball.Speed.X, -ball.Speed.Y);
- }
- else if(pos.Y > (float)_rect.ActualHeight - _ballTexture.Height / 2) {
- pos.Y = (float)_rect.ActualHeight - _ballTexture.Height / 2;
- ball.Speed = new Vector2(ball.Speed.X, -ball.Speed.Y);
- }
- else
- pos.Y += ball.Speed.Y;
-
- ball.Position = pos;
-
- ball.RotationAngle += ball.RotationSpeed;
- }
- }
The next step is drawing the balls, as they’re simply updating positions for now. This is done in another project-supplied method, OnDraw (where we rendered our Silverlight UI):
- private void OnDraw(object sender, GameTimerEventArgs e) {
- SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.LightBlue);
-
- _uiRenderer.Render();
- spriteBatch.Begin();
- spriteBatch.Draw(_uiRenderer.Texture, new Vector2(0, 0), Color.White);
- foreach(var ball in _balls)
- spriteBatch.Draw(_ballTexture, ball.Position, null, Color.White, ball.RotationAngle, new Vector2(_ballTexture.Width / 2, _ballTexture.Height / 2), 1.0f, SpriteEffects.None, 0);
- spriteBatch.End();
- }
That’s basically it. I’ve also added a handler for the “Reset” button that creates randomly a new set of balls (you can look it up in attached code). This is how it looks with several balls all bouncing at different speeds, directions and rotations:

You can simply watch, or catch & drag some ball to change its direction or speed…