Archive for April, 2011

Windows Phone navigation workarounds

Tuesday, April 26th, 2011

Silverlight for Windows Phone has adopted a navigation mechanism reminiscent of a web browser. Each page is authored as a separate resource. The application issues commands to a NavigationService to move from one page to the next. The phone even has a hardware back button. This choice of web-like navigation causes no end of difficulties to application developers.

Navigation in Windows Phone starts with a URI. But rather than identifying an HTML resource, this URI identifies a XAML resource. The application doesn’t create pages; it just identifies them. The runtime creates each page based on the given URI. This causes three problems.

  • Parameters
  • View model location
  • Back-stack modification

Parameters

The URI must contain all of the information required to construct the page. For the main page of the application, this is usually fine. Just bring up the XAML representation of the main menu. But subsequent pages often drill down into detail. If the main page displays a list of articles, and we want to bring up a specific article when the user taps, then we have to identify the article in the URI. All of the article links target the same XAML resource. It’s the data that differs.

To differentiate the links, many developers take the typical web-based approach. They add query string parameters to the URL. Chris Koenig gives an excellent example of parameter-passing. The Silverlight NavigationContext object exposes these parameters via the QueryString property, specifically for this purpose.

The problem with query string parameters is that they requires an application to drop down to string-based identification, rather than rely upon direct object access. To generate the query string, an application has to extract an ID from an object. To consume the query string, it has to look that ID up in an object model. It usually ends up getting right back to the object that it started with. Wouldn’t it be easier to use that object reference directly?

The web was designed for stateless operation. Each request is isolated from the ones that came before. No objects are assumed to be kept on the server for the user’s next request. Each request must contain enough information to reload those objects and generate the required page. This is what allows the web to scale.

But the phone isn’t like a stateless web server. It has rich object state. It exists to serve just one user. It can afford to load objects into memory, and use references among those objects as that user navigates through the application. To drop down to a string only to come back to the same object is not taking full advantage of the platform. What’s good for the web is not necessarily good for the phone.

View model location

The second problem is pairing a view model with a view. Since navigation is based on identifying the view, Windows Phone forces you into a view-first approach. The view is left with the responsibility of finding its view model. To complicate matters, the view must sometimes pass its query string parameters to the view model. The view model uses the parameters to find a reference to the model object.

A common solution to this problem is the view model locator pattern. A view model locator is a single-instance object registered as an application resource. Each view binds its DataContext to a property of this resource, which is an instance of a view model.

    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator"/>
    </Application.Resources>

public class ViewModelLocator
{
    private readonly MainViewModel _main;

    public ViewModelLocator()
    {
        _main = new MainViewModel();
    }

    public MainViewModel Main
    {
        get { return _main; }
    }
}
<UserControl x:Class="ToDoList.MainPage"
    ...
    DataContext="{Binding Main, Source={StaticResource Locator}}">

The biggest problem with the view model locator pattern is that it treats view models as singletons. Since the view model locator is an application resource, there is only one instance serving all of the view models. And since each view data binds to a property, the view model locator can only have one instance of each view model. It is not a view model factory. There is no way to pass query string parameters to a method in order to construct an instance of a view model. You have to write code in the view to pass the parameters to the view model in its DataContext. That one and only instance of the view model must be able to change its behavior to point to a different model instance every time the user navigates.

Back-stack modification

The third problem is removing pages from the back-stack. Some interactions have intermediate steps: the user logs in before seeing content, or a wizard guides a user through a multi-page process to achieve a result. When the user has completed these intermediate steps, they don’t want to return to them. If they have completed the steps prior to reaching the main menu (as in the login example), then they want to exit the application when they hit back from the main menu. They don’t want to see the login screen again. Or if the intermediate steps occur after the main page (as in the wizard example), then they want to return to the main page when they are finished. These intermediate pages should be popped off the stack.

Unfortunately, the Windows Phone OS is completely in charge of the back-stack. It keeps track of each URI that the user visits, and returns to past URIs when they hit the back button. There is no API for removing a URI from the stack. We are left with a couple of hacks. To skip intermediate pages at the beginning of the stack (login), we can exit the application prematurely by throwing an unhandled exception. To skip pages later in the stack (wizard), we can bounce to each intermediate page in the main page’s OnNavigatedTo. Neither solution is particularly appealing.

Conclusion

The Windows Phone navigation system is based on the web metaphor. Unfortunately, the web is the wrong model for a single-user device. The decision to model navigation in this way has caused phone applications to act like web pages. The intent was to bring a well-understood interaction language to the phone. But in practice, it just forced application developers to work around the shortcomings of a misappropriated model.

This decision leads developers into a view-first approach, rather than beginning with the view model. It forces developers to convert object references to strings, only to convert them back into object references. And it requires ugly hacks to produce even the simplest of interactions. If you write Windows Phone apps, prepare to use these workarounds.

How to Make the MacBook Pro Trackpad Less Jumpy

Thursday, April 21st, 2011

To right-click on the MacBook Pro, you put two fingers on the trackpad, then click. To scroll, you put two fingers on the trackpad and move up or down. In Visual Studio, the scrolling is extremely sensitive. When you try to right-click something, it often scrolls out from underneath the mouse. You end up right-clicking on something else entirely.

It seems that the problem is related to the horizontal motion rather than the vertical. If you reduce the number of lines that the mouse rocker moves left and right, the problem subsides. But the Mouse control panel applet won’t let you set this value to zero, so you can’t make it go away entirely.

Unless you hack the registry.

Download the attached file, examine it to make sure you understand what it does, then merge it into your registry. Reboot, and you will be able to right-click without the jumpiness.

Building an occasionally connected Silverlight application with Correspondence

Monday, April 18th, 2011

I posted a to-do list application built with Correspondence. It holds the user’s data in isolated storage, and pushes it to a synchronization service. It took about 56 minutes and 41 seconds to build.

Building an occasionally connected Silverlight application with Correspondence from Michael L Perry on Vimeo.

Correspondence for Silverlight in NuGet

Saturday, April 16th, 2011

With Correspondence for Silverlight, you can create occasionally-connected client applications that run either in or out of the browser. They use isolated storage to save the user’s changes before pushing them up to the synchronization service. From there, they are pushed out to other Silverlight or Windows Phone clients. Create a Silverlight application and use NuGet to add a reference to:

Correspondence.Silverlight.AllInOne

The package will add the following features to your application:

  • Main view model
  • View model locator
  • Model
  • Navigation model
  • Synchronization service

Open the Readme.txt file for instructions on adding the view model locator to App.xaml and MainPage.xaml.

To-do list

As an example, try out this to-do list application. Log in using any user name you like; this example app doesn’t authenticate. You can add tasks, update their name, and mark them completed.

Get Microsoft Silverlight

Some things to try. Log in using your name, enter some tasks, then switch to another user. Those tasks disappear. Switch back and they reappear.

Close the browser, then come back to this page. Your data is still here. Disconnect from the network and this still works.

Now go to a different machine and log in using your name again. At first the list will be empty, but you’ll see tasks come down as the app synchronizes.

A web page that lets you share data between two browsers is nothing new. What makes this different is:

  • Data is still accessible while off line. This is particularly important for out-of-browser applications.
  • There is no application-specific server-side schema or code. The data model and all of your logic is in the client.
  • Silverlight applications can synchronize with Windows Phone applications.

Here’s how the to-do list example is built. Download the source code and follow along.

Log on

A User is a fact identified by a user name. We represent the user in the Factual model:

fact User {
key:
    string userName;
}

Any time we create a User with a give user name, we get back the same instance. This allows the user to log in. Of course, a production system would authenticate the user, but it would still follow the same pattern. The user input is captured first in a transient navigation model:

public class NavigationModel
{
    private Independent<string> _userName = new Independent<string>();

    public string UserName
    {
        get { return _userName; }
        set { _userName.Value = value; }
    }
}

This is where the user name is stored while the user is logging in. We expose this property and a login command through the view model.

public string UserName
{
    get { return _navigationModel.UserName; }
    set { _navigationModel.UserName = value; }
}

public ICommand LogIn
{
    get
    {
        return MakeCommand
            .When(() => !String.IsNullOrEmpty(_navigationModel.UserName))
            .Do(() =>
            {
                User user = _community.AddFact(new User(_navigationModel.UserName));
                _navigationModel.CurrentUser = user;
                _navigationModel.UserName = string.Empty;
            });
    }
}

The login command is only enabled when a user name has been entered. When the user clicks the button, a new User is created with the name that they entered. That User is then stored in the navigation model, and the entered name is cleared out.

List tasks

Once we have a User fact in our navigation model, we can list the tasks assigned to that user. A task is another fact, which references the User to which it is assigned.

fact Task {
key:
    unique;
    User assignedTo;
}

Because the key doesn’t already contain enough information to distinguish one task from another, it is marked as “unique”. This causes Correspondence to generate a new Task every time one is created, rather than looking for an existing one.

The User queries for related tasks.

fact User {
    ...

query:
    Task* openTasks {
        Task t : t.assignedTo = this
            where not t.isCompleted
    }
}

That query is exposed through the view model. The MainViewModel generates a list of TaskViewModels to wrap the Tasks.

public IEnumerable<TaskViewModel> OpenTasks
{
    get
    {
        if (_navigationModel.CurrentUser != null)
            return
                from Task t in _navigationModel.CurrentUser.OpenTasks
                select new TaskViewModel(t);
        else
            return Enumerable.Empty<TaskViewModel>();
    }
}

Add a task

The user can enter the name of a task, then hit the Add button to add it to the list. Just like the user name, the task name is stored in the navigation model temporarily. When a user is logged on and a name has been entered, the button becomes enabled. When clicked, it adds a task assigned to the user, and sets the task name.

public ICommand AddTask
{
    get
    {
        return MakeCommand
            .When(() =>
                _navigationModel.CurrentUser != null &&
                !String.IsNullOrEmpty(_navigationModel.TaskName))
            .Do(() =>
            {
                Task task = _community.AddFact(new Task(_navigationModel.CurrentUser));
                task.Name = _navigationModel.TaskName;
                _navigationModel.TaskName = String.Empty;
            });
    }
}

Change a task name

Notice that the constructor above only takes the User to which the task is assigned. That’s because the User is part of the key. The task name is not. It is a mutable property.

fact Task {
    ...

mutable:
    string name;
}

Because the property is mutable, the user can edit the name and hit the Update button. The button is only enabled when a task is selected and the name has been entered.

public ICommand UpdateTask
{
    get
    {
        return MakeCommand
            .When(() =>
                _navigationModel.SelectedTask != null &&
                !String.IsNullOrEmpty(_navigationModel.TaskName))
            .Do(() =>
            {
                _navigationModel.SelectedTask.Name = _navigationModel.TaskName;
                _navigationModel.TaskName = String.Empty;
            });
    }
}

Mark a task completed

Finally, the user can mark a task as completed. This is itself a new fact.

fact TaskCompleted {
key:
    Task completedTask;
}

The Task fact queries for related TaskCompleted facts to see if it is completed.

fact Task {
    ...

query:
    bool isCompleted {
        exists TaskCompleted c : c.completedTask = this
    }
}

This query is then used in the User’s query so that he sees only the open tasks.

fact User {
    ...

query:
    Task* openTasks {
        Task t : t.assignedTo = this
            where not t.isCompleted
    }
}

When the user clicks the Complete button, it completes the task. We added this method to the Task itself using a partial class.

public ICommand CompleteTask
{
    get
    {
        return MakeCommand
            .When(() => _navigationModel.SelectedTask != null)
            .Do(() =>
            {
                _navigationModel.SelectedTask.Complete();
            });
    }
}
public partial class Task
{
    public void Complete()
    {
        Community.AddFact(new TaskCompleted(this));
    }
}

Because this creates the TaskCompleted fact, it causes the list to refresh, and the task is removed.

Build your own apps

Please download Correspondence and try it out. If you have any questions about building your own models, please contact me by email or Twitter. If you’d like to use my synchronization server, just send me a request for an API key. I’ll be glad to help you get set up.

Correspondence in NuGet

Friday, April 1st, 2011

I have released Correspondence for Windows Phone 7 to NuGet. Correspondence is a NoSQL database for the phone and other occasionally connected clients. While offline, it queues all of your user’s changes. While online, it pushes those changes to a synchronization server, which in turn pushes it to other devices.Create a Windows Phone 7 application and install the following package:

Correspondence.WindowsPhone.AllInOne

This will add models, view models, a view model locator, and a synchronization service to your application.

Models

Correspondence models are expressed in a language called Factual. The package adds a folder called Models that contains a Factual file and a T4 template to parse it. The first thing you’ll want to do after adding the package reference is to hit the “Transform All Templates” button to generate some code.The starter model contains concepts useful for any Windows Phone 7 application. First it has an Identity:

fact Identity {
key:
   string anonymousId;
   ...
}

The Identity fact is uniquely identified by the user’s anonymous Windows Live ID. If they move to a different device, they carry their Identity with them. This makes it really easy to collaborate between users.The model also has the ability to disable and reenable toast notifications:

fact DisableToastNotification {
key:
   unique;
   Identity identity;
query:
   bool isReenabled {
       exists EnableToastNotification e : e.disable = this
   }
}

fact EnableToastNotification {
key:
   DisableToastNotification* disable;
}

The Identity fact queries to see if there are any DisableToastNotification facts:

fact Identity {
   ...
query:
   DisableToastNotification* isToastNotificationDisabled {
       DisableToastNotification d : d.identity = this
           where not d.isReenabled
   }
}

The Identity partial class adds a property that turns these successor facts into a simple boolean property:

public partial class Identity
{
    public bool ToastNotificationEnabled
    {
        get { return !IsToastNotificationDisabled.Any(); }
        set
        {
            if (IsToastNotificationDisabled.Any() && value)
            {
                Community.AddFact(new EnableToastNotification(IsToastNotificationDisabled));
            }
            else if (!IsToastNotificationDisabled.Any() && !value)
            {
                Community.AddFact(new DisableToastNotification(this));
            }
        }
    }
}

Extend these facts and build your model in model.fact. Hit “Transform All Templates” after each change to regenerate the classes. Create partial classes to add your own business logic. ViewModelsThe package also adds a ViewModels folder, which contains two view models:

  • MainViewModel
  • SettingsViewModel

The main view model is just an empty starting place. Add properties to this view model to data bind to controls on your main page.Settings view model has one property started for you. It exposes the ToastNotificationEnabled property in the Identity. This is just a simple pass-through. You don’t raise PropertyChanged events or inherit a base class. Correspondence will raise the PropertyChanged event for you. This works because Correspondence is built on Update Controls.

public bool ToastNotificationEnabled
{
    get { return _identity.ToastNotificationEnabled; }
    set { _identity.ToastNotificationEnabled = value; }
}

The ViewModels folder also contains a ViewModelLocator class. Open the Readme.txt file for instructions on adding this class to your application resources, and referencing it in your views. As you create your own view models, follow the pattern demonstrated with these two existing view models to add them to the locator.

public class ViewModelLocator
{
    private readonly MainViewModel _main;
    public ViewModelLocator()
    {
        ...
        _main = new MainViewModel(_synchronizationService.Identity);
        ...
    }
    public object Main
    {
        get { return ForView.Wrap(_main); }
    }
}

SynchronizationService

Correspondence would be just another isolated-storage-based NoSQL database if it weren’t for the synchronization service. For the most part, this class will be invisible to you. It is initialized in the view model locator, and it works automatically.Every time you store a published fact, the synchronization service wakes up and pushes it to the server. If the device is off-line at the time, the fact is queued. The synchronization service will wake up when the network becomes available and start pushing facts.

When another device publishes a fact to which you have subscribed, the server will send a push notification. The synchronization service responds to these push notifications and adds the facts to the repository. Your app is notified via data binding, and the UI updates.The synchronization service is also watching the ToastNotificationEnabled property. When it is true, it subscribes for toast notifications. When it is false, it unsubscribes.

There are two parts of the synchronization service that you are likely to change. The first is the POXConfigurationProvider. When you create an account with a synchronization server, you will be issued a URL, a user name, and a password. Put these into this class.

public POXConfiguration Configuration
{
    get
    {
        string address = "https://historicalmodeling.com/correspondence_server_web/pox";
        string userName = "<<Your username>>";
        string password = "<<Your password>>";
        return new POXConfiguration(address, "MyCoolWindowsPhoneApplication", userName, password);
    }
}

The second is the subscriptions. The synchronization service subscribes to the Identity. The device will receive any facts published to the user’s Identity. As you develop your own model, you will create other publications. Add linq expressions here to subscribe to those facts.

_community = new Community(IsolatedStorageStorageStrategy.Load())
    .AddAsynchronousCommunicationStrategy(new POXAsynchronousCommunicationStrategy(configurationProvider))
    .Register<CorrespondenceModel>()
    .Subscribe(() => _identity)
    ;

More to come

There is definitely a learning curve for historical modeling in general, and Correspondence in particular. Please review the body of articles here and on Historical Modeling. I will also be posting videos and examples over the next few weeks.I am also opening my synchronization server for a private beta. Please email or mention me to reserve your place. mperry@mallardsoft.com or @michaellperry.