Managing WP7 UI state with Caliburn.Micro’s guard conditions

My first Windows Phone 7 app had a lot of extraneous code whose sole purpose was enabling and disabling pieces of the user interface. Managing the visual state of buttons was one pain point. I ended up with a lot of code that looked like this:

private void ToggleButtons()
{
    if (timer.Status == "running")
    {
        StartButton.IsEnabled = false;
        EndButton.IsEnabled = true;
    }

    else if (timer.Status == "stopped")
    {
        StartButton.IsEnabled = true;
        EndButton.IsEnabled = false;
    }
}

There are about 20 things wrong with that example, but the one I’d like to focus on is how poorly conditional checks like this scale. It’s manageable when I have two buttons, but what if I had 10? Add in a third status code and the code balloons to dozens or even hundreds of lines in a hurry. (While this article focuses on MVVM, if you want to reimplement that example more elegantly in a traditional codebehind style, leave a comment. I’d be interested to see what you come up with.)

The Caliburn.Micro MVVM framework provides an elegant means for handling this scenario. Rather than setting a button’s enabled state manually, Caliburn.Micro allows you to create a boolean property that indicates whether a button can perform its intended function. If the button’s operation can’t successfully execute, the button itself is automatically disabled. Let’s look at a simple example.

Overview of the sample

The sample app illustrates how to implement a common scenario:

  • MainPage.xaml includes a textbox, a textblock and a button.
  • As long as the textbox is empty, the publish button is disabled.
  • When the user enters text in the textbox, the publish button is automatically enabled.
  • Clicking the publish button displays the entered text in the textblock

Dead-simple databinding

Here’s the entire view, minus some boilerplate and formatting attributes:

<Grid x:Name="LayoutRoot">
    <Grid x:Name="ContentGrid">
        <StackPanel >
            <TextBlock Name="PublishedText"/>
            <TextBox Name="TextToPublish" />
            <Button Content="Publish"
                    Name="Publish" />
        </StackPanel>
    </Grid>
</Grid>

I’m using Caliburn.Micro’s convention-based databinding to link the three elements in my UI to properties in the page’s viewmodel. In this case, it’s simply a matter of applying a Name attribute to each element that corresponds to a property or method name in the viewmodel. Caliburn.Micro wires them up automatically.

Properties, action messages and guards

The heavy lifting, such as it is, happens in the viewmodel:

public class MainPageViewModel : PropertyChangedBase
{
    private  string textToPublish;
    public string TextToPublish
    {
        get
        {
            return textToPublish;
        }
        set
        {
            textToPublish = value;
            NotifyOfPropertyChange(() => CanPublish);
        }
    }

    public bool CanPublish 
    { 
        get
        {
            if (string.IsNullOrEmpty(TextToPublish))
                return false;
            else
                return true;
        }
        
    }
    
    public string PublishedText { get; set; }

    public void Publish()
    {
        PublishedText = TextToPublish;
        NotifyOfPropertyChange(() => PublishedText);
    }
}

There are several key elements to this viewmodel. First, note that MainPageViewModel inherits from PropertyChangedBase, which is Caliburn.Micro’s base class implementation of INotifyPropertyChanged. The NotifyOfPropertyChange method is defined in PropertyChangedBase. Which brings me to the second important element…

The NofityOfPropertyChange calls are what tell the view that something has changed and trigger it to update itself. In this case, the TextToPublish property is updated automatically when the user enters text into the databound TextToPublish textbox. The property’s setter then pokes the view and tells it to reevaluate CanPublish.

CanPublish is what is known as a CanExecute guard condition. A guard condition is a boolean property that is paired via a naming condition to a method in the viewmodel. If the guard returns false, it blocks the method from executing, and the corresponding UI element is disabled until the CanExecute condition evaluates to true.

To implement a guard, create a boolean property and append the word Can to the beginning of the method name that the guard is associated with. In the example, CanPublish is guarding the Publish method, which is linked to the Publish button in the view.

TextToPublish kicks the view to check CanPublish, which evaluates whether any text exists in TextToPublish. If the property contains text, CanPublish returns true, and the publish button lights up to let the user know that the button is enabled.

Download the sample

A complete Visual Studio project that implements the example above is available at my Codeplex site. It was built with the February 2011 version of the Window Phone Developer tools. Other than the WP7 tools, there are no external dependencies. The Caliburn.Micro framework code is included in the Framework folder.

Advertisements

Leave a comment

Filed under Caliburn.Micro, MVVM, Windows Phone 7

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s