Thursday, May 24, 2012

Upgrading to 7.1


I upgraded my app project to 7.1 back in late March, but it didn't go smoothly. 

Immediately after upgrading, I wanted to run the project and make sure upgrading hadn't broken anything. Unfortunately the first thing I got was a cryptic runtime Exception: 'WrappedException' with details 'Unspecified Error', breaking when I initialised a boolean for the first time. I googled the exception and found other people complaining that upgrading their projects gave them these errors as well - http://forums.create.msdn.com/forums/t/88547.aspx - the problem seemed to be running the old version of the Silverlight Toolkit or the CodingForFun toolkit. I have both of these, so time to upgrade them through nuget.
But...it turned out I have the most recent version? Crap. Try rebuilding from clean - didn't help. 

I searched again and found two articles both mentioning this error in relation to template bindings - http://www.wirebear.com/blog/2010/10/21/windows-phone-7-unspecified-error/ and http://www.telerik.com/community/forums/windows-phone/databound-listbox/unspecified-error-on-databoundlistbox-for-mango.aspx  so I guess I went through my project and checked the templates on that page.
  1. Commented out both the headertemplate and the jumplist itemtemplate - the app ran fine
  1. Put back in just the header template - app ran fine. So I guess it is /sigh/ somewhere within my horrible nested jumplist template.
  1. Just for fun, put them all back in - fails! The exception detail:

MS.Internal.WrappedException was unhandled
  Message=Unspecified error
  StackTrace:
       at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
       at MS.Internal.XcpImports.UIElement_UpdateLayout(UIElement element)
       at System.Windows.UIElement.UpdateLayout()
.....
 InnerException:
       Message=Unspecified error
       StackTrace:
            at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
            at MS.Internal.XcpImports.UIElement_Measure_WithDesiredSize(UIElement element, Size availableSize)
            at System.Windows.UIElement.Measure_WithDesiredSize(Size availableSize)
            at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(UIElement child, Size layoutSlotSize)
            at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)

 
And I've narrowed it down to this template:
  <DataTemplate x:Key="pivotJumplistTemplate">
            <l:JumpList
               
 ScrollDuration="400"
               
 ItemsSource="{Binding events}"
               
 ItemTemplate="{StaticResource eventTemplateByDay}"
               
 JumpButtonStyle="{StaticResource AccentColoredButtonStyle}">
                <l:JumpList.CategoryProvider>
                    <l:DistinctPropertyValueCategoryProvider PropertyName="StartTime"/>
                </l:JumpList.CategoryProvider>
            </l:JumpList>
        </DataTemplate>

If I replace this one with the non-jumplist, it works.

        <DataTemplate x:Key="pivotListTemplate">
            <ListBox
               
 ItemsSource="{Binding events}"
               
 ItemTemplate="{StaticResource eventTemplate}">
            </ListBox>
        </DataTemplate>

Aha - and now adding Jumplist to my search,  I get this article from the guy who wrote the control I'm using - 
All the comments say they are seeing this error. Turns out the control is now distributed as part of http://wp7contrib.codeplex.com/, which has been updated for 7.1. Installed the new package with nuget and swapped out my assembly references….and got the same exception.  And so were other people since September - I can't find an indication that he's updated it since then. I left a comment on the post asking if it had been updated. He's responded a couple of times since then saying he is planning to update, but hasn't had time recently.

Fortunately Telerik recently had a special for Microsoft employees, so I got their Windows Phone suite free - I can insert their jumplist instead.

Tuesday, March 6, 2012

extracting the hardcoded info


PAX East schedule is out! I need to get cracking on this. I also got another response to my app survey today, where the only feature requested is 'update for pax east'. 

So, last week I implemented the ability to download a hardcoded file from my server. Now I need to adapt that so that I can download whatever files are available, and that I only do this if they are updated from my version.  I want to add this option in an app bar, but I need the collapsed app bar which is only available in mango, and I'm hoping to get one last usable version for pax east out in pre-mango format. So I've added this button in the about page (terrible design, I know). I might also want to add a little notification to the front menu letting the user know if a new version is available?
I should add a 'what's new' popup on first run, like 4th and Mayor.

I wired up a button in the about screen to look for a new schedule on my server, and put a really lame 'version info' file on the server, looks like this
3.1.2012
"East/2012"

So this is - date = last time the server schedule was updated, and location= folder location to look in on the server. In that folder will be a zip file of all the xml files. Each zip needs to be a complete set - I'm not going to try and manage just sending the new events or anything like that. (I'm mostly being inspired here by this article on downloading and reading from a zip - http://www.galasoft.ch/mydotnet/articles/article-2008032301.html

I actually format the event schedule  into xml by hand. I copy the plain text from the official website, then
  1. Remove special characters - /&" are the main ones. Also odd quote chars like ’ and — and …
  2. Manually insert an 'Event' heading for each event
  3. arbitrarily decide on the 'type' of the event, basically I put as 'show' anything that doesn't sound like it'll have audience participation/questions. 
Etc etc

I've hardcoded lots of things that need changing. I haven't gotten a full plan for how to best handle this instead.
  1. Panorama title says' PAX Prime 2011' - updated
  1. Maps are all of Seattle - I have the bcec and boston maps, but will the pax specific ones change? I should probably wait here...nah, I'll almost definitely need to send out another update later. For now let's put in last year's maps.
  1. Useful links are seattle based - updated


public get, private set, public crash?


Goodness,  I seem to have found the weirdest bug. I decided to pull all the event headings into the Schedule class ("Manticore" etc) as a precursor to loading these dynamically from a settings file.  I set up the lists like this:

        
public List<string> eventDays
        {
            
get { return eventDays; }
            
private set { }
        }

However, all of a sudden I found that the app would completely and silently crash, not even throwing an exception for me, when it tried to access any of these list variables - even from within the same class. I removed the get/set so they were just public variables, and the app worked fine again. Then I put back this get/set code, and the app crash reliably reproduced, and then visual studio itself crashed.

    public Schedule()
        {
            
ObservableCollection<Event> events = new ObservableCollection<Event>();
            Events = events;
            eventDays = 
new List<string>();
        }

        private void readSchemaFile()
        {
            
if (eventLocations == null)
            {
                eventLocations = 
new List<String>();
            }
   //populate list
      }


edit: the next day, when it was not 2am, someone pointed out to me that I had obviously put a recursive get on eventDays, so it was crashing with a stack overflow. Way to go, me. 

xaml fiddling


Took a 2 day course at work that gave me a good overview of the changes available in mango, but was overall aimed at a new developer and probably not worth my entire two days. I did spend the time working on the app and updated the search to look and act like marketplace search on the device
  • Got rid of the separate search.xaml so that now it is presented in the schedulepivotview.xaml like any other view of events
  • Had to add a bunch of items to this (search header, search textbox, text to show if a view is empty) and found that if I put it all in a stackpanel, the list of events doesn't scroll (documented online in a couple of places - the list needs to be inside something with a set size, when it's in a stackpanel it thinks it has unlimited viewspace and so doesn’t need to scroll). However if I just put all the items in the top grid and hid the non-relevant ones, then the touch didn't seem to work on the pivot, presumably because other items were 'in the same place'. I worked around this by putting all the extra controls in a stackpanel that was collapsed by default, like this
  • <Grid>
    • <StackPanel>
      • <textblock search header>
      • <textbox search entry>
    • <Pivot>
    • <StackPanel>
      • <textblock empty search text>
      • <textblock empty 'my schedule' text>

  • As a bonus, this made it easy to also implement a notice when the user enters my schedule and has not yet added any items to it.

Also added an inline star to all items that are in your schedule, so you can tell without clicking on details whether you've already added this one.

Sunday, February 12, 2012

Implementing asynchronous testing

So when I had got my test project set up so it at least ran, I started creating a whole set of tests, most of which just do Assert.Inconclusive("Not yet implemented"). Now I'm going through and implementing them one by one.

Class - ScheduleViewModel contains a private instance of the class Schedule. When I call ScheduleViewModel.Load(), it calls Schedule.Load(), which fires an event on completion and then the method ScheduleViewModel.LoadingComplete() handles that event. Unfortunately,  without just making everything public (or internal, but that's not much cleaner) I can't make my test aware of this event, so that it can wait to assess the results of LoadingComplete()

So what I think I'm doing here, is changing the method ScheduleViewModel.LoadingComplete to catch the event from schedule, and throw another one that will be caught by a new ScheduleViewModel.LoadReallyComplete method. This new event will be visible to the test code, so we can wait on it.

 test method:
            _viewModel = new ScheduleViewModel(pivotView, pivotParam);
            Assert.IsNotNull(_viewModel);
 
             // make sure we wait for the ScheduleLoadingComplete to happen            
            _viewModel.VM_ScheduleLoadingComplete += 
                new EventHandler<ScheduleLoadingEventArgs>(ScheduleCallback);
            _viewModel.LoadSchedule();
            // wait for our method to trigger on the event and set this to true
            EnqueueConditional(() => _callbackDone);
 
            foreach (var slice in _viewModel.EventSlices)
            {
                Assert.IsNotNull(slice);
            }
 
        //event handler helper - triggered by the ScheduleLoading event in the ScheduleViewModel, sets _callbackDone to true
        public void ScheduleCallback(object sender, ScheduleLoadingEventArgs e)
        {
            _callbackDone = true;
        } 


class under test:
  public event EventHandler<ScheduleLoadingEventArgs> VM_ScheduleLoadingComplete;
 
        // this method will be called when the Schedule instance finishes loading. It will then throw its own event
        // that will trigger the LoadPopulatedSchedule() method  
        public void Schedule_ScheduleLoadingComplete(object sender, ScheduleLoadingEventArgs e)
        {
            // throw an event for finished loading
            if (VM_ScheduleLoadingComplete != null)
            {
                VM_ScheduleLoadingComplete(this, e);
            }
        }
 
        public void LoadPopulatedSchedule(object sender, ScheduleLoadingEventArgs e)
        {
//does a lot of stuff            // Fire Event on UI Thread
            view.Dispatcher.BeginInvoke(() =>
            {
                view.OnLoadComplete();
            });
        }



Now that I'd come this far, however, I realised that I actually want to fire my event for the test right at the end of LoadPopulatedSchedule, where I'm currently firing the UI event. So I could get rid of my 'trigger on one event, raise another' method, and add the new event to the end of LoadPopulatedSchedule, right after the UI Dispatcher invoke.(It seems like I should be able to make the test trigger on the UI event, but for now this seems close enough)

Of course, once I had everything triggering correctly on events, it turned out that I actually hadn't initialised the data structure correctly in the first place, and then that I was looking at the wrong set of results, and then that I wasn't correctly clearing my test data so that every subsequent test failed. And once I'd solved all them, I found that the UI method being dispatched was calling a method that referred to variables instantiated in the xaml, so were failing with null references when run under the test harness.


Reading material from this session:
basic stack overflow question
http://blogs.infosupport.com/unit-testing-with-silverlight/
http://www.codebadger.com/blog/post/2009/09/08/Unit-Testing-Silverlight-ViewModels-%28MVVM%29-That-Make-Asynchronous-Calls.aspx

Saturday, February 11, 2012

Beginning to test

For the first two releases, I had only manual tests. This was clearly inadequate - I want to make some major changes to the app, and it's going to be pretty annoying to have to go and walk through all the app functionality after each change. I test software for a living, and I strongly believe in testing early and often - I am in theory a fan of test driven development, but I totally fell over when it came to actually building a new project from scratch. Time to fix that.

I began looking into all the test frameworks available for Windows Phone apps. There are several, and I didn't really know which way was going to be 'best' or 'easiest'. I already had the Silverlight Toolkit installed, and was working in a theoretically MVVM framework, so I looked for approaches designed to work with that. I found (among many others) these guides:
I then walked through the setup outlined in the TDD Kata, as far as the beginning of Test #1. Around this stage, I spent maybe two hours trying to get my classes to implement the interface as described, but getting blocked by the way they all inherited from phone specific classes.. So I moved away from getting 'unit tests' per the usual definition here, and wrote some more general tests - mostly only the simple ones that didn't require me building any fake objects. A few specific points that tripped me up
- A test failure (Assert.Fail or even Assert.Inconclusive) is treated as an exception during debugging, and there appears to be no way to turn this off. If, like me, you just wrote a bunch of tests that fail and you want to debug a specific one, you'll just have to Continue a lot.
- to use the (Tag[""]) functionality, you need "using Microsoft.Silverlight.Testing" and not just "using Microsoft.Silverlight.UnitTesting".

The next week, I realised that I wanted to get my app update published, and I didn't want to publish all the new test code I was writing. To get the update published ASAP, I created a new WindowsPhone Test Project, pulled out all the test code (handily saved into the Test folder for easy extraction) and shipped the existing app with a link to my survey added.

When I launched the new test project, I found that it crashed immediately when it started running the tests - and I couldn't run it in debug mode to figure out why. While looking for tips on how I should have set up this project, I found that the creator of this project, Jake Ginnivan, had done the 'building testable phone objects' work for me in the Windows Phone Essentials toolkit. Eventually I discovered that the problem was the exceptions thrown by failed tests (noted earlier) - so the Test Project was essentially useless to me. It's possible I simply missed the option to run it in debug mode, but my solution was to create a regular Windows Phone App project, and put the tests in there where I could safely run under debug mode. While investigating this I found another tutorial - Catel - Part 8 of n: WP7 Mango and unit testing the camera.

So, the current status of the project is
- need to reimplement my core MVVM framework with testable objects
- need to write actual unit tests around each base class
- I have about half the broader tests passing.Currently I'm working on one that fails because it doesn't wait for the asynchronous object population to complete. I think that's worth a whole new post.

While poking around in all these investigations, I also installed these useful looking dev tools, which I haven't yet explored:

PAX Digital Assistant: up to now

My plan for this blog is to be mostly about my app development work - building, testing, designing, using toolkits and frameworks and so on. I have one app under development and ideas for more. This post gives the background of my current app. 

In the beginning - conception, ambition, scaling back, release
Late 2010, when the SDK for Windows Phone had been released and I was all excited about building an app, I realised that I should build an app for PAX. I began, but didn't get anything done in time for PAX of that year. Then I bought tickets to PAX East 2011, and decided that I would have an app out for that. I looked into MVVM programming, and got pretty much my first taste of actually using an MVC pattern (big props to Laurent Bugnion's toolkit). I was practicing all my (underdeveloped) project management skills, creating user stories, sketching out the interface, etc. Shockingly, I didn't give much thought to testing it (pretty egregious oversight, given that I'm an SDET).



Unsurprisingly, my first ideas were ridiculously ambitious - it should interface with twitter, allowing you to follow all the pax-related accounts, and to tweet, and it would automatically append a #pax tag to any tweets you sent, and you should be able to view the map and zoom in from a suburb level right to a room level, and make notes on the map and share them with your friends in realtime. I handwrote the events into a custom, simple-as-possible xml format, then saved this schedule into the app itself (easy at the time, but meant that a full update was required for any schedule changes). As the dates got closer, I started cutting features. I actually got the app through certification about a week before PAX began, and then had to create an update with the full schedule that made it to the app store the day of PAX East 2011. I was unbelievably proud, and seeing the (mostly positive) reviews and getting a few emails from users was an amazing feeling.

version 2 - poor design bites back
I planned to improve it for PAX Prime, August, but in the end didn't really make any changes - my clunky overall design meant that simply updating all the content to be relevant for Prime was an effort. At PAX Prime I had some new users, but still a few bugs.  In particular, some users complained it was crashing frequently, which I couldn't repro. Eventually one of the users figured out that if he switched his region format from Canada to the USA, it stopped crashing - I thought I'd covered all my bases by randomly testing in region formats like french, two cyrillic languages and an asian language, but no. Immediately after PAX I was still motivated enough to do some work, and I fixed this bug as well as implementing a search feature among all the events.

doing it all right this time, for real
Coming up now we have PAX East 2012. I am in the process of redesigning the app under a test driven framework, so that I can add some major new features like exporting your scheduled events to your calendar, sharing them with friends on an associated website, and updating the event list from a website rather than releasing a new version of the app each time the schedule changes.  I created a Trello board to track what I'm doing - I have mostly been pretty consistent at keeping all my notes and sketches on my ipad (I use NoteTaker HD), but a dedicated task tracker seems like it'll make life easier. I decided that it would be useful to get more feedback from users (related: I'm taking a User Centred Design Certificate) so I wrote a survey, piloted it on three friends who used the app, and then published (well, submitted for certification, so far) an update that adds a link to this survey in the about page and a notice the first time the user opens it asking them to go take the survey. I also have some feedback in email already from users who contacted me through my about page.

Next few posts will probably cover
 - how I'm building the test framework for my app, and problems I've run into where my design isn't test friendly
- installing and beginning to work with the Skydrive API
- setting up the website for the schedule to update from