Geofencing in Windows Phone 8.1 WinRT

Geofencing was one of the newest features of Windows Phone 8.1 provided and for the developers it indeed was cool. Previously people did it their way but it's always better to have an API in our hands. So, before digging into that I strongly suggest you guys read my previous 2 articles: The Complete Reference of Map Control in Windows Phone 8.1 RT and Tracking Location in Windows Phone 8.1, if you haven't done that already.

These two can get you started pretty quickly and you'd probably want that. If you have already read my aforementioned 2 articles, I expect you understand how to use a map control in Windows Phone 8.1. We're going to need that later.


Geofencing is a mechanism where you put a virtual boundary around a specific point of interest and you want to interact with the user when you arrive or leave that specific boundary. You seriously can do pretty amazing stuff with it actually.

Initial Work

Now, let's take a more practical approach to this. Every time I go into my room, I am supposed to check my mail. But I usually forget that. How cool it would be if my phone reminds me every time I get into my room and to check my mail? ;)

So, let's go ahead and create a new Windows Phone app and name it GeoFencingTest. Now, let's see how to do that actually.

So, first go over your Package.appxmanifest file and go to the Capabilities Tab and select the Location capability.


Now, when you are done with that, let's move on and start cracking. Before going deeper let's get a basic UI running. And it looks as in following:

And on the XAML part it looks as in the following:
  1. <Grid>    
  2.     <Grid.RowDefinitions>    
  3.         <RowDefinition Height="Auto"></RowDefinition>    
  4.         <RowDefinition Height="4*"></RowDefinition>    
  5.         <RowDefinition Height="8*"></RowDefinition>    
  6.     </Grid.RowDefinitions>    
  9.     <Grid Grid.Row="0">    
  10.         <TextBlock Text="GeoFencing Sample" FontSize="25" Margin="10"/>    
  11.     </Grid>    
  13.     <Grid Grid.Row="1">    
  14.         <Grid.ColumnDefinitions>    
  15.             <ColumnDefinition></ColumnDefinition>    
  16.             <ColumnDefinition></ColumnDefinition>    
  17.         </Grid.ColumnDefinitions>    
  19.         <StackPanel Margin="10">    
  20.             <TextBlock Text="Longitude" Margin="0,0,0,15"  FontSize="20"></TextBlock>    
  21.             <TextBlock Text="Latitude"  Margin="0,0,0,15" FontSize="20"></TextBlock>    
  22.             <TextBlock Text="Altitude"  Margin="0,0,0,15" FontSize="20"></TextBlock>    
  23.         </StackPanel>    
  25.         <StackPanel Grid.Column="1" Margin="10">    
  26.             <TextBlock Name="Longitude" Margin="0,0,0,15"  FontSize="20"></TextBlock>    
  27.             <TextBlock Name="Latitude"  Margin="0,0,0,15" FontSize="20"></TextBlock>    
  28.             <TextBlock Name="Altitude"  Margin="0,0,0,15" FontSize="20"></TextBlock>    
  29.         </StackPanel>    
  31.     </Grid>    
  33.     <Grid Grid.Row="2" Margin="10">    
  34.         <Grid.ColumnDefinitions>    
  35.             <ColumnDefinition Width="4*"></ColumnDefinition>    
  36.             <ColumnDefinition Width="7*"></ColumnDefinition>    
  37.         </Grid.ColumnDefinitions>    
  38.         <Grid.RowDefinitions>    
  39.             <RowDefinition></RowDefinition>    
  40.             <RowDefinition></RowDefinition>    
  41.             <RowDefinition></RowDefinition>    
  42.         </Grid.RowDefinitions>    
  44.         <CheckBox Content="Single Use"></CheckBox>    
  45.         <TextBlock Grid.Row="1" FontSize="20" Text="Dwell Time" Margin="0,8,0,0"/>    
  46.         <TextBox Grid.Column="1" Name="DwellTime"  Grid.Row="1"/>    
  48.         <Button x:Name="CreateGeoFencingButton" Grid.Row="2" Grid.ColumnSpan="2" Content="Create GeoFence" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>    
  50.     </Grid>    
  52. </Grid>  
Before going in deeper into what is for what, let's get some basic stuff done. Let's get our current location first.

Since as you guys have seen in the last articles, it's fairly easy to do so. All I'm doing here is getting the current location using Geolocator and providing the Latitude, Longitude and Altitude into the textblocks defined in the MainPage.xaml. 

  1. public sealed partial class MainPage : Page  
  2. {  
  3.     Geolocator geolocator = new Geolocator();  
  4.     CancellationTokenSource CancellationTokenSrc = new CancellationTokenSource();  
  6.     public MainPage()  
  7.     {  
  8.         this.InitializeComponent();  
  10.         this.NavigationCacheMode = NavigationCacheMode.Required;  
  11.     }  
  13.     protected override void OnNavigatedTo(NavigationEventArgs e)  
  14.     {  
  16.         InitializeLocation();  
  18.     }  
  20.     async private void InitializeLocation()  
  21.     {  
  22.         try  
  23.         {  
  25.             geolocator = new Geolocator();  
  27.             CancellationTokenSrc = new CancellationTokenSource();  
  28.             CancellationToken token = CancellationTokenSrc.Token;  
  30.             var position = await geolocator.GetGeopositionAsync(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30)).AsTask(token);  
  32.             Longitude.Text = position.Coordinate.Point.Position.Longitude.ToString();  
  33.             Latitude.Text = position.Coordinate.Point.Position.Latitude.ToString();  
  34.             Altitude.Text = position.Coordinate.Point.Position.Altitude.ToString();  
  35.         }  
  37.         catch (Exception)  
  38.         {  
  39.             if (geolocator.LocationStatus == PositionStatus.Disabled)  
  40.             {  
  41.                 ShowMessage("Location Services are turned off");  
  42.             }  
  44.         }  
  45.         finally  
  46.         {  
  47.             CancellationTokenSrc = null;  
  48.         }  
  50.     }  
  52.     private async void ShowMessage(string message)  
  53.     {  
  54.         MessageDialog dialog = new MessageDialog(message);  
  55.         await dialog.ShowAsync();  
  56.     }  

The only thing that is interesting here is having a CancellationToken generated from a CancellationTokenSource. Usually these are used if you really want control of your task after it's being fired, the rest of the procedure should look familiar since it's a basic Geolocator usage to find the current geolocation.

Setting up a GeoFence:

Now for the setting up of the actual GeoFence part and even this is fairly simple. The method looks as in the following:  

  1. Geofence geofence = null;    
  2. int DefaultDwellTimeInSeconds = 0;    
  3. private void SetupGeofence()    
  4. {    
  5.     //Set up a unique key for the geofence    
  6.     string GeofenceKey = "My Home Geofence";    
  7.     BasicGeoposition GeoFenceRootPosition = GetMyHomeLocation();    
  9.     double Georadius = 500;    
  11.     // the geocircle is the circular region that defines the geofence    
  12.     Geocircle geocircle = new Geocircle(GeoFenceRootPosition, Georadius);    
  14.     bool singleUse = (bool)SingleUse.IsChecked;    
  16.     //Selecting a subset of the events we need to interact with the geofence    
  17.     MonitoredGeofenceStates GeoFenceStates = 0;    
  19.     GeoFenceStates |= MonitoredGeofenceStates.Entered;    
  20.     GeoFenceStates |= MonitoredGeofenceStates.Exited;    
  22.     // setting up how long you need to be in geofence for enter event to fire    
  23.     TimeSpan dwellTime;    
  25.     dwellTime = DwellTime.Text!=""? ParseTimeSpan(DwellTime.Text) : TimeSpan.FromSeconds(DefaultDwellTimeInSeconds);    
  27.     // setting up how long the geofence should be active    
  28.     TimeSpan GeoFenceDuration;    
  29.     GeoFenceDuration = TimeSpan.FromDays(10);    
  31.     // setting up the start time of the geofence    
  32.     DateTimeOffset GeoFenceStartTime = DateTimeOffset.Now;    
  34.     geofence = new Geofence(GeofenceKey, geocircle, GeoFenceStates, singleUse, dwellTime, GeoFenceStartTime, GeoFenceDuration);    
  36.     //Add the geofence to the GeofenceMonitor    
  37.     GeofenceMonitor.Current.Geofences.Add(geofence);    
  39. }    
  41. private TimeSpan ParseTimeSpan(string DwellTimeInSeconds)    
  42. {    
  43.     return TimeSpan.FromSeconds(Double.Parse(DwellTimeInSeconds));    
  45. }    
  47. private static BasicGeoposition GetMyHomeLocation()    
  48. {    
  49.     BasicGeoposition GeoFenceRootPosition;    
  50.     GeoFenceRootPosition.Latitude = 23.742766;    
  51.     GeoFenceRootPosition.Longitude = 90.417566;    
  52.     GeoFenceRootPosition.Altitude = 0.0;    
  53.     return GeoFenceRootPosition;    

Now, there's quite a bit to catch up on.

The first one is definitely the GeofenceKey. Put a GeofenceKey in position just to identify a specific Geofence. I put a generic string to identify my home Geofence.

Then I called the GetMyHomeLocation() method to set the Geofence center to the location of my room. This will identify the center of our desired Geofence.

And the next thing to define is a radius that will define the radius of our circular Geofence. We are using a Geocircle object to define our Geofence here, thus we are using a center and a radius in meters to define our Geofence. You can definitely see the next thing we did is define our geocircle. Actually the Geofence takes a Geoshape object to define it's radius and currently only a Geocircle is supported.

  1. string GeofenceKey = "My Home Geofence";  
  2. BasicGeoposition GeoFenceRootPosition = GetMyHomeLocation();  
  4. double Georadius = 500;  
  6. // the geocircle is the circular region that defines the geofence  
  7. Geocircle geocircle = new Geocircle(GeoFenceRootPosition, Georadius); 
We now have put a checkbox in our XAML named SingleUse. This is supposed to define whether or not our Geofence is to be used only one time. You can set up a temporary one-time used Geofence using this.
  1. bool singleUse = (bool)SingleUse.IsChecked; 
Now, the next thing we did is we define how our desired Geofence would be treated. Which events are we considering with this Geofence? Should this be fired only when we get into that Geofence or should this will only be considered when we exit the Geofence, or even we remove the Geofence? We can actually select all or a subset of that group. So we used the Logical OR operator to add up all the cases we want our Geofence to react upon.
  1. MonitoredGeofenceStates GeoFenceStates = 0;  
  3. GeoFenceStates |= MonitoredGeofenceStates.Entered;  
  4. GeoFenceStates |= MonitoredGeofenceStates.Exited; 
Let's move on into the time domain now. Now we need to determine how long we need to stay in our favourite Geofence to trigger it's desired events. I put a TextBox in front to define that in seconds, if that is defined, we fire out events from our Geofence in that number of seconds and if not then we fire our events in our default dwell time defined by 0 seconds.
  1. // setting up how long you need to be in geofence for enter event to fire  
  2. TimeSpan dwellTime;  
  4. dwellTime = DwellTime.Text!=""? ParseTimeSpan(DwellTime.Text) : TimeSpan.FromSeconds(DefaultDwellTimeInSeconds); 
You can even define how long a Geofence should be up and running. Like I want my rooms Geofence to be running for the next 10 days.
  1. // setting up how long the geofence should be active  
  2. TimeSpan GeoFenceDuration;  
  3. GeoFenceDuration = TimeSpan.FromDays(10); 
Even with that thing defined, one question remains, even though it will run for 10 days, when is the Geofence activated so it can start counting to that defined 10 days. The answer is right below:
  1. // setting up the start time of the geofence  
  2. DateTimeOffset GeoFenceStartTime = DateTimeOffset.Now; 
Well, the only thing left to do is create our desired Geofence and add it to GeofenceMonitor.
  1. geofence = new Geofence(GeofenceKey, geocircle, GeoFenceStates, singleUse, dwellTime, GeoFenceStartTime, GeoFenceDuration);  
  3. //Add the geofence to the GeofenceMonitor  
  4. GeofenceMonitor.Current.Geofences.Add(geofence); 

Now, that's how to create your own Geofence and add it to the GeofenceMonitor. Now you might wonder whether you'd really need to define all that parameters to create a Geofence. Not actually, the least you need to do is to define an Id and a Geocircle to start your Geofence. ;) The rest of the values would use the defaults.

Handling GeoFence Notifications in the Foreground

We have done all our background work to create a Geofence but we won't be able to do a single thing unless we test our Geofence. Now, we have already specified that our Geofence should trigger events after the aforementioned dwellTime and will trigger events if I enter or leave it. So, I definitely need to attach an event handler at a certain place. Don't I?

Before that, let's create the method stub for the click event handler for CreateGeoFencingButton and start the SetupGeofence() method inside it. If you don't know how to do that, select the CreateGeoFencingButton in XAML, go to properties, select the events tab and double-click on the TextBox.

  1. private void CreateGeoFencingButton_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.    SetupGeofence();  

Then let's add the handler in the end of SetupGeofence().
  1. GeofenceMonitor.Current.GeofenceStateChanged += Current_GeofenceStateChanged; 
Now, let's say we want to show a message every time I enter and exit my room's Geofence. The handler might look like the following:
  1. private async void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)    
  2. {    
  3.     var Reports = sender.ReadReports();    
  5.     await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>    
  6.     {    
  7.         foreach (GeofenceStateChangeReport report in Reports)    
  8.         {    
  9.             GeofenceState state = report.NewState;    
  11.             Geofence geofence = report.Geofence;    
  13.             if (state == GeofenceState.Entered)    
  14.             {    
  15.                 ShowMessage("You are pretty close to your room");    
  17.             }    
  18.             else if (state == GeofenceState.Exited)    
  19.             {    
  21.                 ShowMessage("You have left pretty far away from your room");    
  22.             }    
  23.         }    
  24.     });    

There you go! That's how you set up your Geofence in an app running in the foreground.

Setting up a GeoFence in the background

Now, this is where things get a little tricky. There's a number of steps involved in this.

  1. Create a Windows Runtime Component Project and add it to your solution.

  2. Change Package.appxmanifest to declare the BackgroundTask that has been created.

  3. Register the BackgroundTask.

  4. Handle Geofence Notifications from Background Task.

Create a Windows Runtime Component Project

Usually, background tasks are a Windows runtime component so you need to add one to your solution. Please go over to your solution and add a Windows Runtime Project.

After the new project has been created go to class1.cs and rename it to your liking. I renamed it to BackgroundTask and added an IBackgroundTask interface to the class and implemented it. I didn't write anything afterwards. Let's just keep it like that for a while and move to our GeofenceTest project. Go to the references and add the newly created GeofenceTask.BackgroundGeofenceTask project to it. So our Wp8.1 project now has a reference to the GeofenceTask.BackgroundGeofenceTask project.

Change Package.appxmanifest to declare the BackgroundTask

Now let's scoot over to our Package.appxmanifest file and go to the Declarations tab. From the Available Declarations combobox select BackgroundTask and select the location under the Properties list.

Now on the Entry point field please put the full-qualified assembly name of your newly created background task. Don't get confused. It's fairly easy. Let's have a look at the BackgroundGeofenceTask class first.
  1. namespace GeofenceTask  
  2. {  
  3.     public sealed class BackgroundGeofenceTask : IBackgroundTask  
  4.     {  
  5.         public void Run(IBackgroundTaskInstance taskInstance)  
  6.         {  
  7.             throw new NotImplementedException();  
  8.         }  
  9.     }  

 Now use a name in the "namespace.classname" format so that it leaves us with "GeofenceTask.BackgroundGeofenceTask".

Register the BackgroundTask

Now for the part where you register the BackgroundTask. We need to register the background task to the app so it knows to invoke it one time. The registering method looks as in following: 

  1. private async Task RegisterBackgroundTask()    
  2. {    
  3.     BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();    
  5.     var geofenceTaskBuilder = new BackgroundTaskBuilder    
  6.     {    
  7.         Name = "My Home Geofence",    
  8.         TaskEntryPoint = "GeofenceTask.BackgroundGeofenceTask"    
  9.     };    
  11.     var trigger = new LocationTrigger(LocationTriggerType.Geofence);    
  12.     geofenceTaskBuilder.SetTrigger(trigger);    
  14.     var geofenceTask = geofenceTaskBuilder.Register();    
  15.     geofenceTask.Completed += GeofenceTask_Completed;    
  17.     switch (backgroundAccessStatus)    
  18.     {    
  19.         case BackgroundAccessStatus.Unspecified:    
  20.         case BackgroundAccessStatus.Denied:    
  21.             ShowMessage("This application is denied of the background task ");    
  22.             break;    
  23.     }    
  25. }  
Let's see what we have in here now. The very first one gets the BackgroundAccessStatus. That helps us to know whether our application is capable of accessing BackgroundTasks. Now, let's move up and use BackgroundTaskBuilder to create the background task we intend to create. Now, if you look at the TaskEntryPoint we provided there, youll now realize why we created our Background Task project before and added it to the manifest. Because we are using the same entry point name here. I used a name to identify the background task. This is necessary since if there is another background task with the same name you would get an exception thrown. If you want to know whether there is another BackgroundTask with the same name you can iterate through BackgroundTaskRegistration.AllTasks and then determine whether or not there is one with the same name. You can use a method like the following to do so:
  1. public static bool IsTaskRegistered(string TaskName)  
  2. {  
  3.     var Registered = false;  
  4.     var entry = BackgroundTaskRegistration.AllTasks.FirstOrDefault(keyval => keyval.Value.Name == TaskName);  
  6.     if (entry.Value != null)  
  7.         Registered = true;  
  9.     return Registered;  

I haven't used that in this solution but feel free to definitely use this. You can even unregister to ensure that your Background Task is unregistered to allow for others.
  1. public static void Unregister(string TaskName)  
  2. {  
  3.     var entry = BackgroundTaskRegistration.AllTasks.FirstOrDefault(keyval => keyval.Value.Name == TaskName);  
  5.     if (entry.Value != null)  
  6.         entry.Value.Unregister(true);  

The next thing that comes off is defining the LocationTrigger for the BackgroundTaskBuilder object. So, we defined a new LocationTrigger of type LocationTriggerType.Geofence and used the SetTrigger method to set it up. Then we used a BackgroundTaskBuilder object to register the task and we instantiated a GeofenceTask_Completed event handler for that too.

At the bottom you'll see a switch with backgroundAccessStatus and showing a MessageDialog when it's denied or unspecified.

Handle Geofence Notifications from Background Task

So, let's move to our Windows Runtime Component that is actually the Background Task project and implement the IBackgroundTask interface. A method named:

public void Run(IBackgroundTaskInstance taskInstance)

will pop up, we'd put our regular Geofence event handling in there like there in the Foreground example. Now it looks as in following when we are handling it from the background. 

  1. public sealed class BackgroundGeofenceTask : IBackgroundTask  
  2. {  
  3.     public void Run(IBackgroundTaskInstance taskInstance)  
  4.     {  
  5.         var Reports = GeofenceMonitor.Current.ReadReports();  
  6.         var SelectedReport =  
  7.             Reports.FirstOrDefault(report => (report.Geofence.Id == "My Home Geofence") && (report.NewState == GeofenceState.Entered || report.NewState == GeofenceState.Exited));  
  9.         if (SelectedReport==null)  
  10.         {  
  11.             return;  
  12.         }  
  14.         //We are creating a toast this time as this is running in Background  
  15.         var ToastContent = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);  
  17.         var TextNodes = ToastContent.GetElementsByTagName("text");  
  19.         if (SelectedReport.NewState == GeofenceState.Entered)  
  20.         {  
  21.             TextNodes[0].AppendChild(ToastContent.CreateTextNode("You are pretty close to your room"));  
  22.             TextNodes[1].AppendChild(ToastContent.CreateTextNode(SelectedReport.Geofence.Id));  
  23.         }  
  24.         else if(SelectedReport.NewState == GeofenceState.Exited)  
  25.         {  
  26.             TextNodes[0].AppendChild(ToastContent.CreateTextNode("You are pretty close to your room"));  
  27.             TextNodes[1].AppendChild(ToastContent.CreateTextNode(SelectedReport.Geofence.Id));  
  28.         }  
  30.         var settings = ApplicationData.Current.LocalSettings;  
  32.         if (settings.Values.ContainsKey("Status"))  
  33.         {  
  34.             settings.Values["Status"] = SelectedReport.NewState;  
  35.         }  
  36.         else  
  37.         {  
  38.             settings.Values.Add(new KeyValuePair<stringobject>("Status", SelectedReport.NewState.ToString()));  
  39.         }  
  41.         var Toast = new ToastNotification(ToastContent);  
  42.         var ToastNotifier = ToastNotificationManager.CreateToastNotifier();  
  43.         ToastNotifier.Show(Toast);  
  45.     }  

Now, this looks a wee bit different from the first example. The first change that is noticable is that we are now selecting the reports based on our Geofence id and the report's new state. Since we are in the background now, we are using our Geofence id to get the proper Geofence from the entire list. And since we are now in the background we are using a Toast Notification instead of a MessageDialog to show our notification.

Handling it from the App Side

Now you guys might get confused about what to do with the foreground code we made earlier. Do we need the Current_GeofenceStateChanged event handler anymore? Now here we might need to be a bit careful. Now if we want our app to react differently when it is in the foreground and make some UI changes it is necessary to use a GeofenceTask_Completed event rather than Current_GeofenceStateChanged. And there's another thing to be added. We get our GeofenceMonitor reports using GeofenceMonitor.Current.ReadReports() and this step can only be done once for every change. So if your background reads it first, then your foreground app would not be able to read it. So, we need to save it somewhere when the background reads it so our foreground app can read it from there.

So we are using ApplicationData.Current.LocalSettings to save our state in the Background Task. If you look closely you'd find the following snippet:

  1. var settings = ApplicationData.Current.LocalSettings;  
  3. if (settings.Values.ContainsKey("Status"))  
  4. {  
  5.     settings.Values["Status"] = SelectedReport.NewState;  
  6. }  
  7. else  
  8. {  
  9.     settings.Values.Add(new KeyValuePair<stringobject>("Status", SelectedReport.NewState.ToString()));  

So, in our app side in the GeofenceTask_Completed event handler we'll read the status and fill up a new textblock.

Thus we added a new set of textblocks in the MainPage.xaml as in the following:

  1. <TextBlock Grid.Row="2" Text="Status" FontSize="25"/>  
  2. <TextBlock Grid.Row="2" Grid.Column="1" Name="Status"  FontSize="25"/> 
 Now, our GeofenceTask_Completed event handler looks as in the following: 
  1. private async void GeofenceTask_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)  
  2. {  
  3.     if (sender != null)  
  4.     {  
  5.         // Update the UI with progress reported by the background task  
  6.         await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>  
  7.         {  
  8.             try  
  9.             {  
  10.                 // If the background task threw an exception, display the exception  
  11.                 args.CheckResult();  
  13.                 var settings = ApplicationData.Current.LocalSettings;  
  15.                 // get status  
  16.                 if (settings.Values.ContainsKey("Status"))  
  17.                 {  
  18.                     Status.Text = settings.Values["Status"].ToString();  
  19.                 }  
  21.             }  
  22.             catch (Exception ex)  
  23.             {  
  24.                 ShowMessage(ex.Message);  
  25.             }  
  26.         });  
  27.     }  

Now, if you look closely you will see all we did here is get the "Status" object from our ApplicationData.Current.LocalSettings and posted it on the TextBlock named Status. :)

Now, all we have left to do is to do a little change in the UI and add an extra button to set up the Geofence background task. Now it looks as in the following:

I created the method stub for the new buttons click event too and it looks as in the following:
  1. private async void CreateBackgroundServiceButton_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.     if (IsTaskRegistered("My Home Geofence"))  
  4.     {  
  5.         Unregister("My Home Geofence");  
  6.     }  
  7.     await RegisterBackgroundTask();  

Testing the App on the Emulator

You can definitely test the app on the emulator. Like always click the debug button with an emulator selected as the device and when it opens go to the additional tools button and open the location tab. Select a close location to your Geofence, I did select a close one to my room and the status changed itself to "Entered". It was that easy! You can even try the foreground example in the same way!

Stay frosty! I hope this will help.

Similar Articles