Understand the Reversi app structure
The Reversi sample uses a layered structure known as the Model-View-ViewModel (MVVM) pattern. This structure separates UI from non-UI code, which can simplify debugging, testing, and future development. This topic describes each layer in the sample, the parts in each layer, and how all the parts work together.
The Reversi sample differs from simpler XAML samples that put most of their non-XAML code in code-behind files. Reversi adds code to code-behind files in a few cases, but moves most of its non-XAML code to other layers and uses data binding to connect those layers to the UI.
The Reversi sample also differs from more complex XAML samples that use more advanced techniques, including separate MVVM frameworks. Such frameworks are useful for increasingly complex apps, but the Reversi sample shows that there are benefits to even a simple layered structure built using standard XAML.
This topic assumes that you already know XAML and C#. If you are not familiar with these technologies, see Create your first Windows Store app using C# or Visual Basic.
For a short intro to MVVM, see Using the Model-View-ViewModel pattern.
The Reversi app is divided into the following layers:
- The model layer is implemented by the
ReversiGameComponentproject. This is the core game code that represents the game rules, game state, and artificial intelligence (AI), and is completely independent of the UI.
- The view layer is implemented by the Views folder in the
Reversiproject. This code provides the game UI, which is defined in XAML with extensive use of data binding.
- The view model layer is implemented by the ViewModels folder in the
Reversiproject. This code provides UI binding targets and handles all user interactions, but is otherwise completely independent of the UI.
The model layer is in the
ReversiGameComponent project, which is a Windows Runtime Component project. This includes the core game logic: everything needed to represent the game rules, the changing state of an actual game in progress, and the game AI. This code is in the
Game class and a few small supporting types (
Another benefit of using a separate layer is to keep the core game code as simple as possible. Creating a complete board-game app is much harder than just writing the minimum amount of code possible for the rules of a board game. However, the code for even simple game rules can still be quite complex, so keeping the UI out of this code makes it much easier to write and test than if it were not kept separate.
Because the Reversi project consumes the game engine as a Windows Runtime Component, you can also replace
ReversiGameComponent with a performance-optimized equivalent component written in C++.
The view layer is in the
Reversi project's Views folder and includes the code for the major visual parts of the app, including each page, the settings Flyouts, and the game controls.
Most of these parts have both XAML and code-behind files, but in some cases, the code-behind is just the boilerplate code generated by the Microsoft Visual Studio 2012 app template. Most of the code that would normally be in the code-behind files is in the model and view-model layers instead.
The XAML files contain most of the view code. These files include major use of the XAML Binding markup extension to define data bindings between the XAML and the view models.
Some views also use code-behind to perform tasks that are more difficult to implement in XAML and are unsuited to the view model and model layers. These include:
- Special setup for the data context or data bindings of views.
- Calling UI methods in the XAML API, such as navigation and animation methods.
- Handling UI events to call view-model methods when there is no convenient XAML alternative.
As your app becomes more complex, you may find it useful to refactor these tasks into more components or layers, or to use one of the many MVVM frameworks that provide related services.
Reversi includes three pages:
- StartPage displays the game and help options shown when you first start the app.
- GamePage displays a
PlayerStatuscontrol and a
Boardcontrol full of
- HelpPage displays the game instructions, which include a
Boardfor demonstration and illustration purposes.
These pages were created using the Basic Page and Item Detail Page templates in the Project -> Add New Item dialog box of Visual Studio 2012, so they are subclasses of the
Common/LayoutAwarePage class generated by the Visual Studio app template. This class provides some useful infrastructure code, as described later in this topic.
The main complexity in the UI is in the controls that represent the game board, scoreboard, and clock. These include both user controls and custom controls. The UI for these controls, including some animated state transitions, is defined in XAML. The controls manage the transitions by using custom dependency properties that are data-bound to view-model properties. For more info, see Data binding and Custom dependency properties in Reversi feature scenarios.
Boardrepresents the game board. This is a subclass of UserControl, and displays a Grid panel containing
BoardSpacecontrols and the various game messages (paused game, pass move, and game over).
Boardis a user control because user controls make it easy to define a simple UI part and its functionality in a XAML and code-behind pair. At some point in future development, it might be useful to refactor this into a custom control for greater reusability.
BoardSpacerepresents each space on the game board. This is a custom control that derives from the Button class, taking advantage of the Command property, but replacing the default UI. For simpler UI replacements, you can use a Button and just set the Style property, as demonstrated by the text buttons on the start page.
BoardSpaceis a custom control because it uses a custom dependency property to drive its animated UI transitions. Because it is a custom control, it is defined in the BoardSpace.cs file and the Reversi/Themes/Generic.xaml file.
PlayerStatusrepresents the scoreboard and clock. This is a custom control that derives from the Control class and is defined in PlayerStatus.cs and the Generic.xaml file. This is a custom control because it incorporates
BoardSpacecontrols, and requires greater control over the visual state initialization than a UserControl can provide. Specifically, it uses an OnApplyTemplate method override to initialize the
BoardSpaceto one of two states before the animated transitions are automatically triggered by the data-binding initialization. This method is not available on the UserControl class, where the earliest chance to modify the control after data binding is in a Loaded event handler—too late to prevent the default animated transitions.
At run time, the Reversi controls look like this.
Reversi includes two settings panels, which are implemented as simple user controls in the View/Settings folder:
DisplaySettingsincludes options to show or hide the clock, last move, and valid move indicators.
NewGameSettingsincludes options to change the board size, switch between human and computer players, and change the AI search depth.
The Views/SampleData folder includes XAML definitions of
SettingsViewModel instances. This data is referenced by various XAML UI files in the Views folder in order to display a meaningful view in the designer. It is not used at run time.
The view-model layer is in the
Reversi project's ViewModels folder and includes the non-visual UI code and all code that interacts with the model layer.
As mentioned earlier, the views use the XAML Binding markup extension to bind to view-model properties. The view models, however, have no direct references to the views. Instead, they provide properties and commands for the view to bind to.
View-model properties can provide:
- Direct exposure of model properties.
- Reformatted or type-converted model properties.
- Values calculated from multiple model properties or method-call return values.
- Commands that convert user input into model method calls.
- Values that represent UI or app states that aren't relevant to the model.
For example, the Reversi UI needs to render the state of each space on the board, which is stored in the
Game model object. However, the UI also needs to display indicators about which moves are legal and which spaces were affected by the most recent move. The
Game class includes this info in the form of move-validation methods and the return values of the move methods. However, the view model is necessary to bring this information together into a single property (the this string indexer property) that the view can bind to.
Reversi includes 3 view models:
SettingsViewModelcontains properties that store the current app settings and includes a reference to the
GameViewModelthat represents the current game.
GameViewModelcontains all interactions with the
Gamemodel class and includes a reference to a
ClockViewModelcontains all clock functionality, including display formatting and commands for pausing and starting the clock.
The ViewModels folder also includes:
BoardSpaceStateenumerations, which provide values for some view-model properties.
ShareHelper, which converts the view-model state into text and image data for sharing.
Reversi project also includes some infrastructure code to make everything work together, and some reusable code that supplements the platform libraries.
The main infrastructure files are the App.xaml file and its code-behind, and the Package.appxmanifest file. For more info about these files, see C#, VB, and C++ project templates for Windows Store apps and Using the Manifest Designer.
The Common folder contains files that are suitable for reuse in other projects. Most of these files are generated by the app and item templates in Visual Studio 2012. However, Reversi adds a few files and makes a few small changes to the template-generated files.
These files support common data binding scenarios:
- BindableBase provides the base class for each view model. This class provides reusable change-notification infrastructure code that works with the data-binding system. For more info, see Data binding in Reversi feature scenarios.
- DelegateCommand is added for Reversi, and provides a simple ICommand implementation that lets you define command functionality inline in a bindable property implementation.
- NullStateToVisibilityConverter is added for Reversi, and provides a standard way for bindings to translate non-null values to Visible values and null values to Collapsed values. You can use this converter instead of having to create special view-model properties to perform this translation.
- BooleanToVisibilityConverter performs a similar translation between Boolean and Visibility values. This converter is generated by Visual Studio 2012 templates, but Reversi has modified it to accept a ConverterParameter value that reverses the translation.
These files support page layout and navigation, including suspend and resume:
- LayoutAwarePage provides the base class for each page in the Reversi view layer. This class provides common functionality to support different view states (such as snapped view state and portrait orientation), data-context management, navigation, and interaction with
SuspensionManagerfor preserving app and navigation state upon suspension or termination.
- RichTextColumns provides a panel that renders rich text content in one or more columns as needed by the current screen size, resolution, and view state. Reversi uses this class in the
- SuspensionManager is a template-generated class for saving and restoring temporary app state when your app is suspended or terminated. Reversi modifies this class to enable it to serialize the interconnected view models.
These files provide reusable code and styles:
- SettingsFlyout provides reusable code for implementing settings panes. This code is copied from the Callisto toolkit. Normally, you would just install the Callisto extension from Visual Studio and add a reference to it in your project. Reversi copies the code into the project in order to save you from having to perform this separate installation step before you can run the sample.
- Toast provides a simple toast notification service.
- StandardStyles.xaml is a template-generated ResourceDictionary of standard styles. All styles that Reversi does not use are commented out in order to improve the app's startup performance.
ReversiGameComponentTests project includes unit tests for the
ReversiGameComponent project. These tests were written during the development of the core game logic to check various design assumptions as the code grew in complexity. The complexity made the code somewhat error prone, and these unit tests helped to identify and diagnose bugs and to gradually improve the code design.
The tests are split into 4 classes:
- BasicFunctionalityTests includes tests for the
MoveAPIs of the
Gameclass and features such as undo and redo.
- ValidationTests includes tests for the code that checks whether a particular move is legal.
- AiTests includes tests that verify the behavior of the game AI, which is really just code that evaluates the quality of different moves.
- SerializationTests includes tests for the code that represents game moves and states as strings. This code is useful in the other tests.
These tests provide a small amount of coverage, but were enough to provide significant value during development. More complete coverage—especially tests for the view-model layer—would provide even more value.
Like the other benefits of MVVM, unit testing does not have to be an all-or-nothing matter. Even small amounts of code separation and unit testing can provide great value. In fact, using small amounts at first will help you better understand what works and what doesn't work. That way, you can effectively manage the growing complexity of an app during development, and avoid adding extra complexity before you need it.
For more info, see Creating and running unit tests on a Windows Store app.
- Developing games
- Reversi sample app
- Developing Reversi
- Reversi feature scenarios
- Create your first Windows Store app using C# or Visual Basic
- Roadmap for Windows Store apps using C# or Visual Basic
- Data binding
- Designing great games for Windows
Build date: 3/22/2013