Parking Tickets

The current approach for reminders works on the assumption that you are using a “pay-and-display”-style car park where you pay in advance to park for a certain amount of time.

Another option would be to track how long you’ve been parked and calculate what your current parking fee is for the shopping centre-style parking where you pay on exit.

If you’re interested in this second model then it would be great if you could give me your feedback over on UserVoice.

One of the many (500+ apparently) new features in Windows Phone 7.1 (codenamed Mango) is the ability to set reminders from your application. I’ve been working on the Mango-enabled version of Car Finder and thought it would be great if the user could set a reminder for when their parking ticket is due to run out.

Get to the API Already!

Ignoring the user interface aspects for now, actually creating a reminder is fairly simply and involves using the ScheduledActionService class. This class is actually the base for  Alarm, Reminder, PeriodicTask, and ResourceIntensiveTask, so it’s quite an important class, but I’ll cover alarms and background agents another time.

I’ll quickly summarise how you use the API, and then give you my helper class afterwards, so don’t worry about the details for now.

Alerts.DarkCreating a Reminder

Creating a new reminder is as simple as calling the Add method and passing a ScheduledAction instance. The ScheduledAction instance for a reminder is a Reminder and contains the time for the reminder to occur, the title and content of the reminder, the URI to navigate to if the reminder is tapped, and how the reminder occurs (if at all). The Reminder also has a name, which is used to identify it in the ScheduledActionService.

Deleting a Reminder

Deleting a reminder simply involves calling the Remove method and supplying the name of the reminder that you want to remove.

Getting a Reminder

You can get the details of an existing reminder by using the Find method and supplying the name of the reminder that you want to get. Handily, this gives you the full Reminder instance that you set when you created the reminder.

The ReminderManager Class

So, that’s (briefly) how you manage reminders, so here’s my helper class that achieves all of the above.

As with my EnterKeyHandler, this code is available as part of the Windows Phone 7 from the Trenches repository at BitBucket. It will also be available (as the EnterKeyhandler already is) on the WP7 Contrib project.

namespace DerekLakin.Common
{
    using System;
    using Microsoft.Phone.Scheduler;

    /// <summary>
    /// Provides a static helper class for managing reminders.
    /// </summary>
    public static class ReminderManager
    {
        /// <summary>
        /// Adds a new reminder.
        /// </summary>
        /// <param name="name">The name of the reminder.</param>
        /// <param name="title">The title of the notification.</param>
        /// <param name="body">The body of the notification.</param>
        /// <param name="beginTime">The time of the reminder.</param>
        /// <param name="navigationUri">The URI to be passed to the application on launch.</param>
        /// <param name="recurrence">The recurrence of the reminder.</param>
        /// <returns>The new <see cref="Reminder"/> instance.</returns>
        public static Reminder AddReminder(
            string name,
            string title,
            string body,
            DateTime beginTime,
            Uri navigationUri,
            RecurrenceInterval recurrence = RecurrenceInterval.None)
        {
            if (HasReminder(name))
            {
                RemoveReminder(name);
            }

            var reminder = new Reminder(name)
            {
                BeginTime = beginTime,
                Content = body,
                NavigationUri = navigationUri,
                RecurrenceType = recurrence,
                Title = title
            };
            ScheduledActionService.Add(reminder);

            return reminder;
        }

        /// <summary>
        /// Gets the reminder with the specified name.
        /// </summary>
        /// <param name="name">The name of the reminder.</param>
        /// <returns>A <see cref="Reminder"/> instance if found; otherwise <c>null</c>.</returns>
        public static Reminder GetReminder(string name)
        {
            var reminder = ScheduledActionService.Find(name) as Reminder;
            return reminder;
        }

        /// <summary>
        /// Determines whether there is a reminder with the specified name.
        /// </summary>
        /// <param name="name">The name of the reminder.</param>
        /// <returns>
        ///<c>True</c> if there is a reminder with the specified name; otherwise, <c>false</c>.
        /// </returns>
        public static bool HasReminder(string name)
        {
            var reminder = GetReminder(name);
            return reminder != null;
        }

        /// <summary>
        /// Removes the reminder with the specified name.
        /// </summary>
        /// <param name="name">The name of the reminder.</param>
        public static void RemoveReminder(string name)
        {
            if (HasReminder(name))
            {
                ScheduledActionService.Remove(name);
            }
        }
    }
}

 

Using it in Anger

In Car Finder, I have a method that creates a reminder and it looks (more-or-less) like this:

private void CreateReminder()
{
    // NOTE: The ReminderManager handles removing an existing reminder of the
    //       same name if one exists.
    try
    {
        ReminderManager.AddReminder(
            Constants.ReminderKey,
            this.ReminderTitle,
            this.ReminderBody,
            this.ReminderTime,
            null);
    }
    catch (Exception ex)
    {
        this.IsReminderSet = false;
        MessageBox.Show(
            StringTable.Message_ReminderContent,
            StringTable.Message_ErrorCaption,
            MessageBoxButton.OK);
    }
}

In the constructor for the view model, I do a  check to see if a reminder exists and update the local properties accordingly:

/// <summary>
/// Initializes a new instance of the <see cref="MainViewModel"/> class.
/// </summary>
/// <param name="locationManager">The location manager.</param>
/// <param name="settings">The application-wide settings.</param>
/// <param name="resourceClient">The resource client.</param>
public MainViewModel(
    LocationManager locationManager,
    Settings settings,
    IHandleResources resourceClient)
{
    this._locationManager = locationManager;
    this._resourceClient = resourceClient;
    this._settings = settings;
    
    // ...

    if (ReminderManager.HasReminder(Constants.ReminderKey))
    {
        var reminder = ReminderManager.GetReminder(Constants.ReminderKey);
        if (reminder.BeginTime > DateTime.Now)
        {
            this._reminderTime = reminder.BeginTime;
            this._isReminderSet = true;
        }
        else
        {
            this._reminderTime = DateTime.Now;
            this._isReminderSet = false;
        }
    }
    else
    {
        this._reminderTime = DateTime.Now;
        this._isReminderSet = false;
    }
}

When the toggle switch to set a reminder is cleared, I remove the reminder like so:

public bool IsReminderSet
{
    get
    { 
        return this._isReminderSet; 
    }

    set
    {
        if (this.UpdateProperty("IsReminderSet", ref this._isReminderSet, value))
        {
            if (this._isReminderSet)
            {
                this.CreateReminder();
            }
            else
            {
                ReminderManager.RemoveReminder(Constants.ReminderKey);
            }
        }
    }
}

That’s pretty much all there is to it. I hope you find it useful.

About these ads