A couple of days ago I got a really nasty surprise, I went to open To Do Today to add something to remember to do later that day and was shocked to see the message "To Do Today has been revoked by Microsoft, please uninstall this app". Wondering what sort of rule I had broken to have this happen to me I raced to my email and saw that I'd received nothing from Microsoft. Browsing the marketplace on the phone and the web showed that To Do Today still looked like it was certified and available for purchase.
The shoe dropped when I tried to open Left to Spend and received the same message. Since I'd developed both of these apps neither was actually purchased through the marketplace, they had been side-loaded on to the phone. I quickly checked my Marketplace account and verified that my phone was still listed as "developer unlocked", but to test this I decided to redeploy the app to the phone. Surprisingly this failed with an error message informing me that my phone was not developer unlocked.
Pulling open the developer unlock tool I retried unlocking the phone to no effect. The solution ultimately involved deregistering the phone against my account and then registering it again. As soon as the phone was registered all previously failing apps loaded successfully.
My advice if you see this message is "don’t panic", especially if you haven't received any notifications from Microsoft. Most likely you've run into some weird issue like this.
In my previous post I talked about the benefits of using co-routines in Caliburn Micro to ease any interactions with the View from the View Model. In that case it was the use of the Visual State Manager; in this post we’ll cover managing storyboards and animation.
We’ll use code from an older post around how to create one off event handlers. What I’ve done is encapsulate that logic into an extension method ToObservable.
public static IObservable<IEvent<EventArgs>> ToObservable(this Storyboard storyboard)
{
if(storyboard == null)
throw new ArgumentNullException("storyboard");
return Observable.FromEvent((EventHandler<EventArgs> e) => new EventHandler(e),
e => storyboard.Completed += e,
e => storyboard.Completed -= e);
}
In the BeginStoryboardResult we verify the view is a FrameworkElement (and therefore can contain Resources). We then load the Storyboard from the Resources collection. Using the extension method we wire the Completed event of the Storyboard to the completion of the IResult.
public class BeginStoryboardResult : ResultBase
{
private readonly string storyboardName;
public BeginStoryboardResult(string storyboardName)
{
this.storyboardName = storyboardName;
}
public string StoryboardName
{
get { return storyboardName; }
}
public override void Execute(ActionExecutionContext context)
{
if(!(context.View is FrameworkElement))
throw new InvalidOperationException("View must be a framework element to use BeginStoryboardResult");
var view = (FrameworkElement)context.View;
if(!view.Resources.Contains(StoryboardName) || !(view.Resources[StoryboardName] is Storyboard))
throw new InvalidOperationException(String.Format("View doesn't the contain a Storyboard with the key {0} as a resource", StoryboardName));
var storyboard = (Storyboard)view.Resources[StoryboardName];
storyboard.ToObservable().Take(1)
.Subscribe(e => OnCompleted());
storyboard.Begin();
}
}
After that it’s pretty much just starting the actual storyboard.
Again one of the main benefits of result an IResult like this is we still maintain separation between the view model and the view, we can now create unit tests that test how the view model plays storyboards without requiring the actual storyboard.
I’m pleased at announce that both the Mango updates for To Do Today and Left to Spend have passed certification and are available on the Windows Phone Marketplace.
To Do Today 2.0 adds the following:
- Support for fast app switching.
- Customisable live tiles, including a background agent to ensure tiles are kept up to date when the date changes.
- The ability to pin categories to the home screen.
- Set custom reminders for tasks.
Left to Spend 2.0 adds:
- Support for fast app switching.
- A live tile to let you glance and go about how much money you have left to spend all from the home screen. A background agent keeps this up to date even during date changes.
Well it's been quite a while since I've posted anything having spent the last five weeks in Canada getting married and St Lucia on our honeymoon. As usual a lot happens while you're away, with Mango getting closer to release (and the marketplace opening for Mango apps), the unveiling of Windows 8 at Build and other smaller news. With all this there's been a lot to catch up but after five weeks away from development I've been itching to get back to it. I’m currently working on Mango updates for Left to Spend and To Do Today, I’m taking the opportunity to rebuild bits of To Do Today with some of the techniques I’ve learnt in the last year so I’ll hopefully be discussing some of those as I go.
One of the cool and often over looked features in Caliburn Micro is the IResult interface and its use in Coroutines, there's some excellent documentation on the Caliburn Micro website so I won't go into a lot of detail regarding how they work. One of the aspects I really like (besides helping to simplify asynchronous code) is that they better enable View, View Model separation even when you need to interact directly with the View.
A great example of this is the Visual State Manager, the visual state of a screen is something that there's a definite use case to control from the View Model as it’s a smooth way to have animated states within the page. Previously my approach has been to expose a string "State" property on the View Model and bind this to a custom attached dependency property. This works but I feel it has a few weaknesses, a page can be in multiple states at any one time due to Visual State Groups (the page will be in a state for each group). This isn't represented well by the State property and in reality really hides that fact. It also doesn’t control the need to turn on and off state transitions.
Because the ActionExecutionContext passed to the IResult has a reference to the View we can manipulate the Visual State Manager directly in the IResult without worrying about bindings. We’ve also preserved the distinction between the View and View Model so we can unit test our View Model changes the state without execution of the IResult.
So what does the code look like, pretty simple really, I have a ResultBase class to handle some of the plumbing in IResult. From this class I create my VisualStateResult that takes the appropriate parameters. On Execute we verify the View is a Control and then invoke GoToState.
public abstract class ResultBase : IResult
{
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
protected virtual void OnCompleted()
{
OnCompleted(new ResultCompletionEventArgs());
}
protected virtual void OnError(Exception error)
{
OnCompleted(new ResultCompletionEventArgs
{
Error = error
});
}
protected virtual void OnCompleted(ResultCompletionEventArgs e)
{
Caliburn.Micro.Execute.OnUIThread(() => Completed(this, e));
}
public abstract void Execute(ActionExecutionContext context);
}
public class VisualStateResult : ResultBase
{
private readonly string stateName;
private readonly bool useTransitions;
public VisualStateResult(string stateName, bool useTransitions = true)
{
this.stateName = stateName;
this.useTransitions = useTransitions;
}
public string StateName
{
get { return stateName; }
}
public bool UseTransitions
{
get { return useTransitions; }
}
public override void Execute(ActionExecutionContext context)
{
if(!(context.View is Control))
throw new InvalidOperationException("View must be a Control to use VisualStateResult");
var view = (Control)context.View;
VisualStateManager.GoToState(view, StateName, UseTransitions);
OnCompleted();
}
}
yield return new VisualStateResult("Complete", useTransitions: false);
One of the recommendations from Microsoft for better performance from your WP7 application is to begin work on your page in the first LayoutUpdated event after OnNavigatedTo.
In MVVM frameworks this wasn't the easiest to achieve, Ben Gracewood wrote an awesome post on how you can achieve this in Caliburn Micro 1.0 by creating your own FrameAdapter. I recommend reading this post for this as well as its discussion on co-routines (one of the lesser used features of Caliburn Micro).
In the 1.1 release the process becomes a little easier, the class ViewAware (from which Screen derives) has a method called OnViewReady that will be called on the first layout updated event after OnNavigatedTo.
protected internal virtual void OnViewReady(object view);
There's one small problem this this method, it's no a co-routine, something I'm making more and more use of in my projects. So how can we go about extending this?
Thankfully it's pretty easy to invoke Actions in CM, so on the OnViewReady method we invoke an action of the same name passing in the view (this is important since the results in the co-routine may want to interact with the view).
We can then create a virtual OnViewReady co-routine method that does nothing. All done!
public abstract class ViewModelBase : Screen
{
protected override void OnViewReady(object view)
{
Caliburn.Micro.Action.Invoke(this, "OnViewReady", (DependencyObject)view);
}
public virtual IEnumerable<IResult> OnViewReady()
{
yield break;
}
}
On a personal note, I'll be out of the country for the next five weeks getting married to a fantastic canadian girl so the blog will obviously be a little quiet. I may need to sneak back for a post or two since a semi secret Windows Phone project I've been working on is going to be launched by the client in the next month.