Freigeben über


Building a WPF Emulator Part II

OK, this time we’ll get to some code. (and a new blog theme style that makes fitting code a lot easier!) In previous posts I’ve outlined the concepts involved with links to more detailed info on the general patterns etc… Now we’ll have a look at some actual code for a .NET Micro Framework device emulator.

Look Ma – no Main()

You can create a WPF based application from the Visual Studio project templates. It will create a basic application with a main window. One thing you will notice straight off, if you haven’t done any WPF programming before, is that the .CS code files are not quite where you’d expect. They are a node under the application and window .XAML files. The application.cs file is practically empty and so is the window.cs file. If you are anything like me you’ll be pulling your hair out and screaming at your computer screen “Where the #$%*! is Main()?”. Funny thing about using WPF and XAML – it’s not needed. The XAML code will be used to generate one for you! (Yeah, I know that’s a bit creepy, but you get used to it in time! ;-) )

The application

To work with the emulator you need to modify the application.cs file to start the emulation engine. This is a bit different from the standard way in which you normally do things in a Forms based emulation. Traditionally you start the UI from within the emulation object by starting a new thread for the UI. I’ve always thought that was a bit backwards as all the UI templates etc.. for Forms and WPF make the UI start and run on the applications main thread. So I decided that with a new WPF library it was worth working with the tools and templates rather than against them. Thus the UI runs on the main thread as expected and the emulation engine runs on a background thread.

 using System;
 using System.Windows;
 using Microsoft.SPOT.Emulator;
 using Microsoft.SPOT.Emulator.Wpf;
  
 namespace KioskEmulator
 {
     public partial class App
     {
         KioskEmulatorEngine Engine;
         KioskEmulatorViewModel ViewModel;
  
         protected override void OnStartup(StartupEventArgs e)
         {
             base.OnStartup( e );
  
             // create a new emulator instance
             KioskEmulatorEngine eng = 
                 new KioskEmulatorEngine(new EmulatorNative());
  
             // let the view model connect to the emulator events
             // *before* starting the emulator, otherwise it might
             // miss the initialize event. (E.g. try to connect
             // after the one time event is fired.)
             this.ViewModel = new KioskEmulatorViewModel(eng);
  
             this.Engine = eng;
             this.Engine.StartEmulator( );
         }
  
         protected override void OnActivated(EventArgs e)
         {
             base.OnActivated(e);
  
             // Setting the DataContext here instead of in XAML
             // is an optimization (see: 
             // https://msdn.microsoft.com/en-us/library/cc656914.aspx )
             // it also ensures that the engine the viewmodel connects
             // to is started before the databinding starts trying to
             // access it.
             // only hook up the data context the first time the
             // Application is activated
             if( this.MainWindow.DataContext == null )
                 this.MainWindow.DataContext = this.ViewModel;
         }
  
         protected override void OnExit(ExitEventArgs e)
         {
             base.OnExit(e);
  
             // shut down the emulator engine if it isn't already
             // shutting down
             if(  Engine.State != Emulator.EmulatorState.ShutDown
               && Engine.State != Emulator.EmulatorState.Uninitialize
               )
             {
                 Engine.Stop();
             }
         }
     }
 }

The application code is pretty simple really. There is a custom class KioskEmulatorEngine that is derived from the standard Emulator class provided by Microsoft.  There is also a Custom ViewModel called KioskEmulatorViewModel that overrides the OnStarup method to create a new View Model and emulation engine. It then binds the two together and starts the emulator running. (Note: the use of new EmulatorNative() as the parameter to a custom EmulatorComponent derived class is to support custom interop in the emulator’s HAL – that’s an entirely different set of blog articles for a later date. ) OnExit handles shutting down the emulator if it isn’t already in the process of shutting down. The OnActivated() method is a bit special it handles setting the DataContext for data binding. This is done in the OnActivated() handler for two reasons. First off it is a performance optimization as recommended by MSDN documentation. Secondly it helps to ensure that the Emulator is ready to be accessed by data binding (through the ViewModel) before actually starting any binding operations. (We’ll get to data binding in more details when we look at the XAML code in a later post)

The following is a diagram of the core classes involved in the application:

image

Click the image to enlarge.

Emulatro2 is a new class derived from the standard Emulator to add events for the Initialize and Uninitialize handling. It is part of the standard WPF emulator library created for this sample.

In my next post we’ll take a look at the KioskEmulatorEngine implementation and then at the ViewModel. The application, emulator engine and the ViewModel for the heart of the emulation. With just those components you can fully automate and unit test the emulator without any need for a visible UI. That’s pretty cool. This is all due to the power of the Model+View+ViewModel pattern used in WPF.

Comments

  • Anonymous
    April 06, 2009
    This was helpful, but what is the concept of using Microsoft.SPOT.Emulator;.

  • Anonymous
    April 07, 2009
    The comment has been removed