Xnaml Component

I am very proud to announce the public beta of Xnaml, a Silverlight plugin for Xna on WIndows Phone 7, Xbox 360 and Pc. Making user interface with Xna it a too long and boring task. I’ve made a plugin that load Xaml page and c# sub code to reproduce the main feature of the Silverlight technology :

  • Dependency Properties
  • Inheritance DP (FontProperty, ForegroundProperty, DataContext, …)
  • Storyboards
  • Binding
  • Xaml parseur
  • Resources
  • Render Transform
  • Easing animation
  • Generics/Theme.xaml files
  • Style
  • Template
  • VisualStateManager
  • and so on …

And main known controls :

  • Border
  • Button
  • ContentControl
  • Grid
  • Image
  • ItemsControl
  • ItemsPresenter,
  • ControlPresenter
  • RootElement (similar to Window)
  • ScrollViewer
  • ScrollContentPresenter
  • StackPanel
  • TextBlock
  • Canvas
  • TextBox
  • Panel
  • Page

And specifc controls :

  • Iphone Scoller
  • Panaorama
  • WP7 Date picker

 

I respect all the WPF hierarchy : DispatcherObject-> DependencyObject-> Visual -> UIElement -> FrameworkElement/FrameworkContent

 

Just Xna !

 

My engine is designed to run in a pure Xna environement on all supported device. My engine is extensible, you can add your own controls, inherit from base classes (such as Control or Pane) to make your own behavior. The compatibility with Xaml is complete. Create your interface on Blend and make a simple copy/past action to add the Xaml file in your Xna project ! Extract a C# code from a Silverlight project and just add it to your own Xna project !

Getting started

The Xnaml Plugin is based on two Assemblies :

  • Arcane.Xna.Windows with contains the main Silverlight classes adapted to Xna
  • Arcane.Xna.Windows.Controls witch contains the main controls (Button, PanoramaControl, etc.)

Reference this two Dlls in you Xna project :

Add a using reference in your game class like this :

using Arcane.Xna.Windows;

Then create a new Arcane.Xna.Windows.XnamlGameComponent object and add it to the component list of your game class :

            XnamlGameComponent component = new XnamlGameComponent(this);
            this.Components.Add(component);

The Silverlight plugin is now ready !  And the Application.Current object is instanced and ready to use. We just have to fill its RootVisual property.

Lets try to add a first user interface. We will make the Application bar of the Windows Phone as a sample :

The first hing to do is to create the fonts we need here. Add to sprite font to the content project. The first will be called NormapSpriteFont and will create a sprteshhet for a Segoe UI with a size of 20. The second will be named SmallSpriteFont and will have the same font family with with a font size of 10.

Add a reference to the font identifier to the Application object to
define the default font to use in TextBlock and ContentPresenter : For that, just add after the last instruction this line :

            Application.Current.DefaultFontAssetName = “NormalSpriteFont”;

Now create a sub directory to your project named Presentations. We will add in this folder all your xaml file and associed c# file. Right click on this directory and add a new Xml file named MainPage.xnaml :

Add this content :

<?xml version=”1.0″ encoding=”utf-8″ ?>
<Page
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    x:Name=”Page”
  xmlns:phone=”clr-namespace:Arcane.TowerDefense.Controls.Phone;assembly=Arcane.TowerDefense”
  xmlns:interface=”clr-namespace:Arcane.TowerDefense.Controls.Interface;assembly=Arcane.TowerDefense”
    WindowTitle=”Page”
    FlowDirection=”LeftToRight”>

  <Grid x:Name=”LayoutRoot”>
   
  </Grid>
</Page>

That an easy to undertand Xaml code. The Page is a container control to host your interface. It can contain only one control. Here this orphan control is a grid, named LayoutRoot. Save this file and change its compilation mode to EmbeddedResource.

Now add a C# classic file named MainPage.xnaml.cs. Add the same using instruction to this file and change the code to :

   public class MainPage : Page
    {
        public MainPage()
        {
            Application.LoadComponent(this, new System.Uri(“/XnamlWindowsPhoneGame;component/Presentations/MainPage.xnaml”, System.UriKind.Relative));
        }
    }

Now the C# and xnaml file are linked. Add this instruction in the Initialize game method :

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            Application.Current.RootVisual = new Presentations.MainPage();

            base.Initialize();
        }

And run the application. You will see nothing else than the cornflower blue screen. Lets add some color.

Change the MainPage.xnaml content to add a Background to the LayoutRoot grid :

  <Grid x:Name=”LayoutRoot” Background=”#FFFF0000″>
   
  </Grid>

Relaunch the application, now the screen is red :

Add Some margin to the grid to see once again le back blue screen :

  <Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>
   
  </Grid>

Now add some children. Lets try a Canvas, StackPanel and Grid childrens :

  <Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>

    <Canvas Margin=”-10″ Background=”#CCFFFFFF”></Canvas>
    <StackPanel Width=”50″ Height=”30″ Background=”Yellow”></StackPanel>
    <Grid Margin=”20″ Background=”#CCCCCC”></Grid>
   
  </Grid>

If you launch the application now, you get a dirty screen like this :

That’s normal : all children are layout uppon each others. Add some columns and row to layout this :

  <Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>

    <Grid.ColumnDefinitions>
      <ColumnDefinition></ColumnDefinition>
      <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition></RowDefinition>
      <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>

    <Canvas Margin=”-10″ Background=”#CCFFFFFF”></Canvas>
    <StackPanel Grid.Row=”0″ Grid.Column=”1″ Width=”50″ Height=”30″ Background=”Yellow”></StackPanel>
    <Grid Grid.Row=”1″ Margin=”20″ Background=”#CCCCCC”></Grid>
   
  </Grid>

Relaunch the application you will have this :

Now lets try to add some texte and some pictures to this interface. I downloaded from web some picture like this :

to add to my interface. I put this icons in a folder named Icons in the content project :

 

Now lets begin to create an application bar.

Change the layoutroot Grid for this :

   <Grid Name=”LayoutRoot”>

      <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width=”Auto”></ColumnDefinition>
      </Grid.ColumnDefinitions>

      <Grid x:Name=”WorldZone” Background=”Transparent”>
    
      </Grid>

      <Grid x:Name=”MenuGrid” Grid.Column=”1″ Width=”72″ Background=”#1F1F1F”>

        <Grid  x:Name=”ThreePointButton”
               HorizontalAlignment=”Left” VerticalAlignment=”Top”
               Background=”Transparent” Margin=”0,10″
               Width=”72″ Height=”36″>
          <Image  Source=”Icons/ThreePoints” Width=”32″ Height=”16″ Margin=”20,5″/>
        </Grid>

        <StackPanel x:Name=”CliffButtons” Orientation=”Vertical” HorizontalAlignment=”Left” VerticalAlignment=”Center”>

          <Grid x:Name=”RiseButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width=”Auto”></ColumnDefinition>
              <ColumnDefinition Width=”12″></ColumnDefinition>
              <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Image  Source=”Icons/calend” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
            <TextBlock Text=”Calendar” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
          </Grid>
          <Grid x:Name=”SunkButton”  Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width=”Auto”></ColumnDefinition>
              <ColumnDefinition Width=”12″></ColumnDefinition>
              <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Image  Source=”Icons/compas” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
            <TextBlock Text=”Compas” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
          </Grid>
          <Grid x:Name=”LevelingButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width=”Auto”></ColumnDefinition>
              <ColumnDefinition Width=”12″></ColumnDefinition>
              <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
                 <Image  Source=”Icons/info” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″ RenderTransformOrigin=”0.5,0.5″>
              <Image.RenderTransform>
                <ScaleTransform ScaleX=”0.5″ ScaleY=”0.8″></ScaleTransform>
              </Image.RenderTransform>
            </Image>

         <TextBlock Text=”In your face” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
          </Grid>
          <Grid x:Name=”RampButton”  Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width=”Auto”></ColumnDefinition>
              <ColumnDefinition Width=”12″></ColumnDefinition>
              <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Image  Source=”Icons/info” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
            <TextBlock Text=”info” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
          </Grid>

        </StackPanel>

        <StackPanel Orientation=”Vertical” Margin=”200,20″ HorizontalAlignment=”Left” VerticalAlignment=”Top”>

          <TextBlock Text=”Menu item 1″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
          <TextBlock Text=”Menu item 2″ Foreground=”White”  HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
          <TextBlock Text=”Menu item 3″ Foreground=”White”  HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
          <TextBlock Text=”Menu item 4″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>

        </StackPanel>
      </Grid>

    </Grid>

Wow that’s bigger 🙂 The LayoutRoot have to column, the first take all the place it can, the second take only the place asked by its children. The second children is the Application bar, it takes 72 pixel like the UI specification said. At the top with an VerticalAlignment tp top i put 3 points to expand, collapse the application bar. I use a StackPanel to layout my icons. And icon is an image and a small text at the left that is not visible in the collapsed state.Just for the fun you will notice that i put to the last icon a rendertransform to scale the Image. To finish, i put another StackPanel with menu items. If you launch it you will see this :

Are we on Silverlight or Xna here oO ? 🙂 Yes that’s pure Xna !

Lets try to add the expanded state and use some storyboards. Open the MainPage.xnaml.cs file we’ve created before. Override the OnApplyTemplate and try to thet the UIElements named “ThreePointButton” and “MenuGrid” in the xnaml file :

        public Grid MenuGrid
        {
            get;
            set;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            MenuGrid = this.GetTemplateChild(“MenuGrid”) as Grid;

            Grid grid = this.GetTemplateChild(“ThreePointButton”) as Grid;
            if (grid != null)
                grid.Tap += new RoutedEventHandler(grid_Tap);
        }

        void grid_Tap(object sender, RoutedEventArgs e)
        {
           
        }

We try to get the Grid and if it suceed we connect to the Tap event. Be sure to intercept tap event that your grid have a visible background (with an Alpha different of 0). Add a boolean to the MainScreenc lass named expanded. It will inform us if the application bar is expanded or not.

bool isExpanded;

Add this utility function to the end of the MainScreen class :

        public DoubleAnimation CreateAnimation(DependencyObject obj, DependencyProperty prop, double fromValue, double toValue, double milliseconds, EasingMode easing)
        {
            CubicEase ease = new CubicEase() { EasingMode = easing };
            DoubleAnimation animation = new DoubleAnimation
            {
                Duration = new Duration(TimeSpan.FromMilliseconds(milliseconds)),
                From = fromValue,
                To = Convert.ToDouble(toValue),
                FillBehavior = FillBehavior.HoldEnd,
                EasingFunction = ease
            };
            Storyboard.SetTarget(animation, obj);
            Storyboard.SetTargetProperty(animation, new PropertyPath(prop));

            return animation;
        }

I use this function inside my Silverlight project we no changes !

It create a DoubleAnimation on the specified object/property from the specified value to the specified value.

To correct errors add two more using :

using Arcane.Xna.Windows.Media;
using Arcane.Xna.Windows.Data;

Now fill the tap event method :

          void grid_Tap(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Storyboard storyboard = new Storyboard();
            if (isExpanded)
            {
                storyboard.Children.Add(CreateAnimation(MenuGrid, FrameworkElement.WidthProperty, 500, 72, 200, EasingMode.EaseOut));
            }
            else
            {
                storyboard.Children.Add(CreateAnimation(MenuGrid, FrameworkElement.WidthProperty, 72, 500, 200, EasingMode.EaseOut));
            }
            storyboard.Begin();
            isExpanded = !isExpanded;
        }

We ask the engine that the event is handled. We change the expanded state and launch a new storyboard. Launch the application, you will have this :

[View:http://www.youtube.com/watch?v=nDP_iAAL9JQ:550:0]

 

As you can see, the Xnaml component is very simple and 100% compatible with Silvelright/WPF. In some case we can have better performance in Xna for UI than Silverlight with its compositor thread. We will see in next tutorial how to use template/style.

You can look at this video to see a sample of me that recreate the panorama control very easely by a simple copy past from an old codeproject about panorama and pivot control.

[View:http://www.youtube.com/watch?v=VgI9SCbURU4:550:0]

 

[soon]

 

Valentin

 

19 thoughts on “Xnaml Component

  1. Great job! Please let us know when you got a version ready for public testing 😉

    I wondered how different you are from RedBadger’s XPF? Could you post a quick blog entry about it?

  2. I want some beta testers before release the link 🙂
    The different with XPF ? i full compatible with Silverlight 🙂 I have more controls and functionnalities

  3. Hey Valentin! Congrats for this nice framework!

    Si tu veux, je peux tester ta version beta! Tu peux me contacter par Twitter (@robertos_br) ou par mail (robertos (at) virtualdreams (point) com (point) br).

    A+!

  4. Projet fort intĂ©ressant et qui permet de crĂ©er des interfaces relativement “simplement” pour le peu que l’on connaisse WPF ou Silverlight…

    Parce que ce taper tout du code pour faire une interface sous XNA c’est un peu gĂ©nant; ils auraient pu prĂ©voir le GUI dans le framework…

    Mais bon lĂ  nous aurons une solution de rechange plus que viable…

    Par contre, avez-vous rĂ©Ă©crits toutes les classes du framework Silverlight pour ĂȘtre utilisable sous XNA ? Parce que je n’ai lu nul part que Silverlight pouvait tourner sous X360, et comme vous dites que XnamlComponent tourne sous X360, j’ai comme un doute…

    Par contre pour ĂȘtre bĂȘta testeur, oĂč faut-il signer ?

  5. Absolument incroyable, c’est vraiment trĂšs fort, et c’est tout Ă  fait ce que beaucoup de monde doit rechercher : la simplicitĂ© de crĂ©ation d’interface de Silverlight alliĂ© Ă  l’incroyable puissance de XNA !

    Si jamais tu as montĂ© / monte une entreprise dans le dĂ©veloppement de jeux XNA pour windows phone, et que par hasard tu commence Ă  recruter des Concepteurs de jeu / des dĂ©veloppeurs, n’hĂ©sites pas Ă  nous transmettre des coordonnĂ©es pour que l’on puisse te joindre !

    Vivement que tout ça soit partagé !!

Leave a Reply

Your email address will not be published. Required fields are marked *