I recently blogged about Flashcards.Show Version 2 for WPF, Silverlight, and Windows Phone, which features the Flashcards.Show application. I’m not going to (again) review the app, but I do want to talk about how we developed the application and the design the code base to support multiple clients.
The first version of Flashcards.Show was a Windows (WPF) application. This app was originally designed by IdentityMine, and used a few Windows 7 features such as multi-touch and taskbar integration. While the first version was great, we wanted to increase its value by enabling users to share the decks that they are creating. Therefore, when we set to work on version 2, we sought both functional and technological solutions to enable ease of use for the deck-sharing scenarios, as well as ease of development and maintenance of the code.
Ease of use for a deck-sharing scenario is achieved by enabling users to simply click one button to start the sharing process, and another to send the deck. Behind the scenes, the application communicates with Windows Azure Flashcards services and uploads the deck. To keep it simple, we chose to use the default email client application as the means for sending the email. The pre-populated email that is generated includes a link to a Silverlight player that lets the email recipients view and interact with the attached deck. If you want to experience it first hand, you can try by clicking this link. The email also includes information on how to download the deck to your Windows Phone application and how to install (using ClickOnce) the WPF application.
Sharing Code between WPF, Silverlight and Windows Phone
After we designed deck sharing, our next step was to build the Silverlight viewer. We knew that we were going to target Windows Phone as the next platform, and therefore our first decision was to make sure the runtimes are compatible. This drove the decision to build the viewer as a Silverlight 3 rather than Silverlight 4 application. While this decision costs us a few days of hard work to implement SL4 features in SL3 code, it paid off during the Windows Phone development phase.
The second decision was to share as much code base as possible, which we did. The Flashcards.Show source code includes a solution file that includes all the “client” (WPF, Silverlight, and Windows Phone) projects. If you’re interested, you can find another solution file that includes all Flashcards.Show projects, including Windows Azure in the WindowsAzureService folder (once you extract the zip file). . For now, we’ll focus on the client projects:
- FlashCards.ViewModel.WPF – Contains the View-Model piece of the MVVM architecture that is used in the Windows application
- FlashCards.ViewModel.SL – Contains the View-Model piece of the MVVM architecture that is used in the Silverlight application
- FlashCards.ViewModel.Phone – Contains the View-Model piece of the MVVM architecture that is used in the Windows Phone application
- FlashCards.UI.WPF – Contains the main Windows application, including both modes, Admin and Game
- FlashCards.UI.SL – Contains the Silverlight application, including the different pages and resources
- FlashCards.UI.Phone – Contains the Windows Phone application, including the different pages and resources
Looking at the above list, you might be asking yourself if there are duplications between the different ViewModel projects and the UI projects. To start with, we have to compile for the target framework. The assembly that is used for WPF ViewModel .NET 3.5 is not supported by Silverlight or Windows Phone. In addition to the Silverlight assembly, Silverlight 3 also is not fully supported by Windows Phone. Therefore you have no other option but to compile to the required target CLR.
But there is more to it than this, especially in regard to the ViewModel project. Since all clients basically share the same data model, they all have the same application logic, display the same games, and follow the same game rules. Therefore both the Silverlight and Windows Phone view-model projects include links to most of the FlashCards.ViewModel.WPF view-model project. The WPF view-model contains the data model for the deck of cards (cardDeck.cs), which is comprised of individual cards (cardPair.cs), which again are comprised of two sides of a card (card.cs). The model includes metadata (MetaData) information about the types of items (text, image, sound, video, URL) placed on each card. The games logic is also part of the view-model as you can see in the LearningGameViewModel.cs and the MatchingGameViewModel.cs. Feel free to further explore the code.
If you review the Flashcards.ViewModel.SL and Flashcards.ViewModel.Phone projects, you’ll see that they are virtually identical, and the code files in each of these projects simply contain links to the original WPF view-model files.
However, a more careful review of the Flashcards.ViewModel.SL reveals some differences. For example, the Silverlight view-model doesn’t have the Taskbar.cs file, since it doesn’t integrate with the Windows 7 taskbar as the WPF application does. The Silverlight version also doesn’t include the DeckPackaging.cs file, since we don’t allow the Silverlight viewer to edit and upload decks to the Windows Azure service.
We omit files and classes of features that are not functional in the Silverlight and Windows Phone solutions. You might want to note that the Flashcards.ViewModel.Phone is identical to the Silverlight view-model.
But there are additional changes that reflect the differences between the different platforms. In the view-model projects, you can find them in the MainViewModel.cs file. The WPF and Silverlight versions of this file are quite different from each other. The Windows Phone code is embedded into the Silverlight project and we use WINDOWS_PHONE and SILVERLIGHT conditional compile time symbols to distinguish between the two. Reviewing the MainViewModel.cs file, you’ll notice compile time conditional statements such as: #if WINDOWS_PHONE
The reason we decided to use compile time symbols instead of creating a complete new copy of the MainViewModel.cs file in the phone project is due to the simple fact that while there are differences between the two, they are small and relatively easily encapsulated.
For example, the Windows Phone application can save decks in local store, a feature we are not using in Silverlight (although possible). This introduces a completely new set of features, like getting a deck from isolated storage over the network, which can be encapsulated for the Windows Phone implementation, and abstracted from the main view-model logic. We simply make sure the main view-model receives the required information for its internal data model, and when the code compiles and runs on Windows Phone, we make sure we wrap the additional functionality in such a way that it is transparent to the main view-model logic.
For example, the StartLoading function is implemented for Silverlight and Windows Phone. While the code is similar in nature, In the Windows Phone implementation you’ll notice that we need to jump through extra hoops. For example, in the webClient_OpenReadCompleted method (called…), we don’t just return a stream back to the view-model, we also write the deck to the isolated storage. During the write time, we show a progress report, because such operations on a Windows Phone can take some time.
Another example is the private _instance_PropertyChanged method that is used in Windows Phone to control the navigation between the application pages, where in the Silverlight version we simply swap in and out user controls instead of complete pages.
- Make your data model technology-agnostic as possible
- In your view-model, separate the way you handle data (the model) and the flow (screen, pages, etc.) of the application (the view) within your application logic. This will make it easier to introduce different behaviors and code for different platforms, just as we did for Windows Phone and SL
Sharing UI (XAML) Is Difficult
This brings us to the next topic of sharing UI and XAML. While sharing the View-Model is relatively straightforward, sharing the UI, is a completely different story.
To start with, there is no #if def support for XAML. Therefore, you can’t use compile time symbols to control which XAML code end up in which project. Next, the namespaces are different. WPF uses a System.Windows.Window, whereas Silverlight uses System.Windows.Controls.UserControl. But even if you successfully overcome the namespace problem, there is a bunch of functionality in WPF4 that is not in Silverlight 3 (remember we chose SL3 for ease of migration to Windows Phone). Therefore, we end up rewriting most of the Silverlight application. With that said, you can still leverage all of your .NET and WPF skills as you write the Silverlight XAML, using data binding, date templates, and such. However, I really hope Shawn’s work on 3-Screen Coding Is Here: Portable Library Tools allow you to target multiple .NET platforms with one binary will help reduce such friction in the near future.
While converting the WPF solutions to support Silverlight 3 was a pain, we deliberately targeted Silverlight 3 and not Silverlight 4 because Windows Phone Silverlight runtime is version 3. The reason is simple; we wanted the easiest possible port from Silverlight to Windows Phone. And the outcome was just that, a super easy port from Silverlight to Windows Phone. It took about 3 days to make the Silverlight application run on Windows Phone.
If you look at the FlashCards.UI.Phone project, you’ll find that most of the files are links to the Silverlight UI project. The differences are visible when we check the displaying screens. In Windows Phone Silverlight application there is only one way to display data – inside a Windows Phone Page. Therefore the Windows Phone and Silverlight solutions differ in that way. But even here, the Silverlight and Windows Phone versions are very similar.
For example, the Windows Phone LearningPage.xaml includes a LearningGame user control (LearningGame.xaml). If you look at the Silverlight LearningGame.XAML, you’ll find the same user control. While we had to copy the XAML file and make some changes to fit the smaller screen, the core of the control, its behavior, and the code behind are very (very) similar. Therefore, even if we did end up copying XAML files, the core functionality remains the same.
- Unfortunately, we can’t really share XAML code
- Some controls can be reused
Obviously, there is no single silver bullet solution to sharing code across multiple platforms. With that said, while working on this project, we learned that there is a lot of room to navigate the platform’s limitations.
- Using MVVM in your WPF/SL solution makes it easier to share the model. Your application data models, logic and any request to the server side backend can and should be shared.
- As for your UI, well, that really depends on the complexity of your design, and how closely you want your implementation to be dependent upon the platform form factor, like the phone’s small screen. However, even here there is some flexibility.
You are more than welcome to download the project source code, which includes some documentation. And please watch a short video on C9 demoing the 3 client applications. As usual, your feedback is most welcome.
I want to thank Arik Poznanski, from Sela group, who helped drive the second phase of Flashcards.show.
Follow Windows Phone announcements on Twitter at WP7DEV
Follow Yochay on Twitter
(Post edited by Barbara Alban)