MVVM on a Windows Store App

I blog for a couple of reasons:

  1. Professionalism – to think and write about a topic at least once a week
  2. Marketability – when I talk to people about jobs, I can point them to my blog to see how I code (and think about coding).  To me, it is much more effective and insightful than a exam or esoteric interview questions
  3. To keep track of stuff for me -  I write stuff down so I don’t have to remember something.

That last point came back to me today.  I wanted to take a break from F# so I looked at MVVM in a Windows RT application.  I went to refresh my brain on MVVM so I hit up Bing and Google.  All of the recent articles that I ran across talked about MVVM –as an after thought.  They were all pimping MVVM helpers like relay command, frameworks like MVVMLight, and other non-core MVVM concepts.  All important to be sure, but non related to MVVM.

I then hit up my own blog and sure enough – I blogged about MVVM 2 years ago when I did a Windows Phone 7 app and I could see just the MVVM in action.  So then I fired up a basic Windows RT application and added 3 folders to it: Models, Views, and ViewModels.

I then added a Model like so:

  1. public class Person
  2. {
  3.     public Int32 Id { get; set; }
  4.     public String FirstName { get; set; }
  5.     public String LastName { get; set; }
  6. }

 

I then added a View Model

  1. public class PersonViewModel: INotifyPropertyChanged
  2. {
  3.     private Person _person = null;
  4.     public event PropertyChangedEventHandler PropertyChanged;
  5.  
  6.     public PersonViewModel(Person person)
  7.     {
  8.         _person = person;
  9.     }
  10.  
  11.     public Int32 Id
  12.     {
  13.         get { return _person.Id; }
  14.         set
  15.         {
  16.             PropertyChanged(this, new PropertyChangedEventArgs("Id"));
  17.             _person.Id = value;
  18.         }
  19.     }
  20.     public String FirstName
  21.     {
  22.         get { return _person.FirstName; }
  23.         set
  24.         {
  25.             PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
  26.             _person.FirstName = value;
  27.         }
  28.     }
  29.     public String LastName
  30.     {
  31.         get { return _person.LastName; }
  32.         set
  33.         {
  34.             PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
  35.             _person.LastName = value;
  36.         }
  37.     }
  38.  
  39. }

I then added a View like so:

image

and then in the code behind of the View:

  1. public PersonView(PersonViewModel viewModel)
  2. {
  3.     InitializeComponent();
  4.     this.mainGrid.DataContext = viewModel;
  5. }

 

Then in the main page, the ViewModel is injected into the View:

  1. public partial class MainWindow : Window
  2. {
  3.     public MainWindow()
  4.     {
  5.         InitializeComponent();
  6.         Person person = new Person(){Id=0,FirstName="Test",LastName="Person"};
  7.         PersonViewModel viewModel = new PersonViewModel(person);
  8.         PersonView view = new PersonView(viewModel);
  9.         view.Show();
  10.     }
  11. }

 

And we have data binding:

image

 

Now I know this is not a complete project and that many patterns are helpful (esp. the relay command one), but this is the core of making MVVM work the MSFT way: data binding and IPropertyNotifyChanged.

Windows Store Apps and Bing Maps

I started creating a RoadAlert client application to be used on RT tablets.  One of the first stumbling blocks was using Bing maps.  I downloaded the SDK easily.  However, when I went to add the maps to my project, I got this:

Capture1

What I had to do was change the project deployment FROM Any CPU to ARM so that the references would resolve:

Capture2

I was then able to get the reference:

Capture3

The problem is then when I ran the app on my developer workstation:

Capture

What I needed to do was the change the project type to x64 so that it would run locally.  Then, when I created the package, I only targeted ARM and then it ran great on my tablet.

Unit Testing Windows RT Apps

I started building some Unit Tests for a windows RT application and I ran into 2 gotchas. 

#1) The file system moves in a test

Well, not really.  But consider this desktop application.  There is a folder called LookupData with an .xml file in it.

clip_image001

I wrote some code that accesses this file via the desktop application and it runs fine:

private async void Button_Click_1(object sender, RoutedEventArgs e)

{

StorageFolder storageFolder = await Package.Current.InstalledLocation.GetFolderAsync("LookupData");

StorageFile storageFile = await storageFolder.GetFileAsync("ObjectiveType.xml");

XmlDocument xmlDocument = await XmlDocument.LoadFromFileAsync(storageFile);

Debug.WriteLine(xmlDocument.InnerText);

}

I then crated a class library that access the same file.

clip_image002

When I run a unit test against this class library, the same code throws an exception:

clip_image003

It looks like Unit Tests add another layer to the path.  Here is the original:

clip_image004

And here is the Tests:

clip_image005

I am guessing MSFT will say that I should be using a Mocking Framework.  The problem is that if I want to do integration tests, I can’t.  Sigh!

#2) You need to make sure all of your tests are async and return a Tasks if they call a async method

I figured out my path problem when I ran into another problem.  I have this set of code wired up:

public async Task LoadFromXML(String path)
{
ObjectiveTypes = new List<ObjectiveType>();
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(path);
XmlDocument xmlDocument = await XmlDocument.LoadFromFileAsync(storageFile);
XDocument xDocument = XDocument.Parse(xmlDocument.GetXml());
var data = from ot in xDocument.Descendants("ObjectiveType")
select ot;
ObjectiveType objectiveType = null;
foreach (var d in data)
{
objectiveType = new ObjectiveType();
objectiveType.ObjectiveTypeId = (Int32)d.Element("ObjectiveTypeId");
objectiveType.ObjectiveTypeDescription = (String)d.Element("ObjectiveTypeDescription");
ObjectiveTypes.Add(objectiveType);
}
}

To unit test, I wrote the following code

[TestMethod]
public void LoadObjectiveTypeFromXML_LoadsSuccessfully_Test()
{
CampaignVictoryConditionFactory factory = new CampaignVictoryConditionFactory();
StorageFolder storageFolder = Package.Current.InstalledLocation;
String path = storageFolder.Path + @"\Tff.Core\LookupData\VictoryCondition_Campaign.xml";
await factory.LoadFromXML(path);
int notExpected = 0;
int actual = factory.CampaignVictoryConditions.Count;
Assert.AreNotEqual(notExpected, actual);
}

But then I get the compiler complaining:

Error 1 The ‘await’ operator can only be used within an async method. Consider marking this method with the ‘async’ modifier and changing its return type to ‘Task’.

I then changed the test’s signature and it ran:

public async Task LoadObjectiveTypeFromXML_LoadsSuccessfully_Test()