XAML and GIS

So many apps are using third party services to display data. Some of these services may give detailed information in HTML format. Why would they give information in HTML? Simple it’s universal. Everyone can display HTML. All of the platforms have some form of a webview control to display HTML. I recently came across such a service that actually gave information in both plain text and HTML. The plain text did not offer the detail that the HTML content did. So I set out to create a way to display the HTML inside a TextBlock. You may ask why I did not use a Webview control and I’ll say with a smile “Because I didn’t want to”. I’ll be 100% honest here, I took some pointers from the HtmlAgilityPack. I should note that this is not intended to display an entire website. You can adjust it to work, but just don’t.

To tackle this task I created a new Behavior that would adjust the text of a TextBlock when it was loaded. The Runtime Interactivity SDK does not include a base Behavior class like the other Interactivity SDKs. Instead of implementing the interface every time I want to create a behavior, I like to use a base Behavior class.

publicabstractclass Behavior<T> : Behavior where T : DependencyObject

{

protected T AssociatedObject

{

get { returnbase.AssociatedObject as T; }

}

protectedoverridevoid OnAttached()

{

base.OnAttached();

if (this.AssociatedObject == null) thrownew InvalidOperationException("AssociatedObject is not of the right type");

We’ll first start by listening to a few events of our TextBlock. The behavior will listen to the Loaded and the LayoutUpdated event. We need to listen to these events because the TextBlock does not have a TextChanged event. The TextBlock will first load but if you are getting data from a service, the text will not be populated yet. The LayoutUpdated event will let us know when the text is populated.

The UpdateText method will convert the text to XML via the XElement class, traverse the nodes to add text elements and then unsubscribe from all events. We’ll assume the text of the TextBlock will not change again.

privatevoid UpdateText()

{

if (AssociatedObject == null) return;

if (string.IsNullOrEmpty(AssociatedObject.Text)) return;

string text = AssociatedObject.Text;

// Just incase we are not given text with elements.

string modifiedText = string.Format("<div>{0}</div>", text);

// reset the text because we will add to it.

AssociatedObject.Inlines.Clear();

try

{

var element = XElement.Parse(modifiedText);

ParseText(element, AssociatedObject.Inlines);

}

catch (Exception)

{

// if anything goes wrong just show the html

AssociatedObject.Text = text;

}

AssociatedObject.LayoutUpdated -= OnAssociatedObjectLayoutUpdated;

AssociatedObject.Loaded -= OnAssociatedObjectLoaded;

}

The ParseText method is the meat to this whole meal. We’ll check the type of each element to determine what to do. If we find a <u> element we’ll start adding underline text. If we find a <b> element we’ll add bold text and so on.

// Add two line breaks, one for the current text and the second for the gap.

if (AddLineBreakIfNeeded(inlines))

{

inlines.Add(new LineBreak());

}

Span paragraphSpan = new Span();

inlines.Add(paragraphSpan);

currentInlines = paragraphSpan.Inlines;

break;

case ElementLi:

inlines.Add(new LineBreak());

inlines.Add(new Run { Text = " • " });

break;

case ElementUl:

case ElementDiv:

AddLineBreakIfNeeded(inlines);

Span divSpan = new Span();

inlines.Add(divSpan);

currentInlines = divSpan.Inlines;

break;

}

foreach (var node in element.Nodes())

{

XText textElement = node as XText;

if (textElement != null)

{

currentInlines.Add(new Run { Text = textElement.Value });

}

else

{

ParseText(node as XElement, currentInlines);

}

}

// Add newlines for paragraph tags

if (elementName == ElementP)

{

currentInlines.Add(new LineBreak());

}

}

Most of the checks are pretty straight forward. We do see two cases with a unique call to AddLineBreakIfNeeded. We see this in the div, ul, and p tags. The point of this is to avoid adding line breaks when we see html like

<div>

<div>

<p>

</div>

</div>

We wouldn’t want to add line breaks for the start of each div and paragraph. In fact we wouldn’t want to add any. We do also add a followup line break for any paragraph tags. This does have a side effect of adding a line when one is not needed like the following

<p>Hello</p>

This does put a line break in when we really don’t need one. For the services I’ve used I haven’t seen this too often.

To check if we do need to add a line break at the start of the elements, we need to check the previous InlineCollection to see if the last item in there was a LineBreak.

/// <summary>

/// Check if the InlineCollection contains a LineBreak as the last item.

/// </summary>

/// <paramname="inlines"></param>

/// <returns></returns>

private static bool AddLineBreakIfNeeded(InlineCollection inlines)

{

if (inlines.Count > 0)

{

var lastInline = inlines[inlines.Count - 1];

while ((lastInline is Span))

{

var span = (Span)lastInline;

if (span.Inlines.Count > 0)

{

lastInline = span.Inlines[span.Inlines.Count - 1];

}

}

if (!(lastInline is LineBreak))

{

inlines.Add(new LineBreak());

return true;

}

}

return false;

}

Now that we have the behavior ready, we need to test it out. First let’s create some sample data. I’ll use the following:

"<p>This is a test of using <u>underline</u> text</p>",

"<p>This is a test of using <b>bold</b> text</p>",

"<p>This is a test of using <i>italics</i> text</p>",

"<div>This is a test of using<p>Nested elements with </p><ul><li>one</li><li>two</li></ul><p>items</p></div>",

"This is a test with an <p>element inside</p>the text",

"<div>This is a test of using<div>multiple nested</div><div>divs within<div>each other</div></div></div>",

"<span>This is a test of using elements</span><span> that we are not testing</span>",

"This is test without any elements"

Put that into a collection of a class and bind an ItemsCollection to it

Microsoft announced today a new SDK to help monetize your Windows Phone apps. This SDK, called Ad Mediator allows you to integrate multiple ad providers into your app. We all know that PubCenter has not been performing well, even Microsoft. So, the tools team built this SDK to help developers easily earn money through ads. This is not a new concept. Windows Phone has had the AdRotator control for some time.

Advantages of using Ad Medator

The Ad Mediator will cycle between any of the ad providers that you configure. You are not guaranteed to get 100% fill rate. You are not guaranteed to get high eCPM. But you are guaranteed that if one provider does not have an ad, another provider will be used.

Installing and using the SDK

Precautions

I found that there are some things you need to be careful of.

You must download and install the ad provider SDKs before configuring Ad Mediator. You do not need to download the SDKs for PubCenter, AdDuplex, Smaato, or Inneractive. These are available as NuGet packages and Ad Mediator will install them fine. For all other providers, download the SDK and manually reference the assembly.If you do not, you will see this dialog with configuring.

You must add the required capabilities to the manifest file. Ad Mediator will not modify your manifest file. If you do not add the required capabilities your app will crash when Ad Mediator tells the provider to get an ad.

Some ad providers take time to validate your account or app. You will not be able to see ads until this is complete.

Some providers require a link to download your app. You will not be able to see ads until this is complete.

Platform matters

Other notes

Refresh rates must be between 60 – 120 seconds. This is just silly. If I want my ad to change at 30 or 45 seconds, I should be able to.

You have to add the control to your page from the toolbox and drag it onto the designer.

You can only configure the rate of ads shown per provider through Dev Center. You will not be able to test failover or % fill while testing

You will only see test ads when running in the emulator.

Dev Center seems to have hard coded values for percent distribution. Here’s the problem. I uploaded an app with five providers. One of those I only want to use as a back up and the others 25% each to try them out. 25% is not an option. I can choose 20 and I can choose 30, but nothing in between. These values may change based on the number of ad providers you configure. So if you configure three, maybe 33% is an option. However these numbers are set, it needs to change to allow for equal distribution in these cases.

When you update your app after you have already added Ad Mediation, you have to set the distribution again! You’d think this would keep the values.

I recently found out about some great sites that are available to help you build a brand for you app. These sites allow you to build a color palette or get custom fonts that help brand the app you are building. This is only a small list and if you know about others, please add a comment.

Responding to user reviews has been positive for me. I wanted to share a few of the positive results with everyone.

Matt responded to my email saying the 1 star rating was an oversight and updated his review

There was a day when an app stopped getting information from services and some people reviewed the app poorly because it wasn’t working. These reviews were valid because the app stopped working. I was able to fix the issue and responded to users.

And like most developers I was effected by the In App Purchase bug the store had in September. Again users started posting poor reviews. Once again I was able to reply to these reviews.

There are many examples of users updating their response during this event and I am so glad I have the capability to respond to users when things like this happen!

Unfortunately I am not able to get a response from every user that I contact. Users will reply or update their review if they feel you have actually tried. And there are plenty of examples of users who did not update their app.

There are a lot more examples where users do not update apps and I’m ok with that. I still have the ability to contact users and maybe they will update their review. For me, this feedback mechanism has been very positive and I encourage everyone to use it.

Some time ago Microsoft announced that all app publishers to the Windows Phone Store had the ability the respond to users reviews of their apps. Many publishers have taken advantage of this functionality and many have not. Responding to reviews is simple. All you need to do is log into DevCenter, check out the reviews of your app(s) and respond to any that you wish.

You can respond to negative reviews or positive reviews. I like to respond to any user that has rated my app three stars or less. I want to know why a user thinks the app is only a 1-3 star app and ask how they think I can improve the app. If they provided a reason for the 1-3 star rating I’ll try to clarify any confusion there may be.I also like to respond to any user asking for a particular piece of functionality. I will tell the user that what they are asing for is either in progress, will be worked on next, or will be taken into account for future work.

One thing I kept on wondering was: “How is my feedback being delivered to the user?” Some users would reply to me and some users would not. Some users would reply within a couple of days and some would take weeks. To test this out I reviewed one of my apps with my normal Microsoft ID (my publisher Microsoft ID is different from my day to day ID).

When the review came into DevCenter I quickly replied.

I hit send and within a couple of minutes I had a new email from Microsoft!

I was amazed. The email was sent immediately. I was thinking that maybe it would go out the next day (I had replied to the review around 9pm) or maybe within a couple of days. I was surprised when the response came immediately. I was mostly surprised due to lack of responses from users. It took days to get a response from users (if they replied at all).

The email that users receive contains your support email address from DevCenter so there no need to put this into your response. This hasn’t stopped me from always including my support email anyways. I want users to know that I want them to contact me. The email also encourages users to change their response. This is pretty cool if you are responding to a user that rated your app poorly. They can also flag you, the developer, as abusing this form of feedback. We have seen cases were publishers were flagged by a user when they probably should not have been. This could have been confusion on the part of the user or the developer. Make sure that what you respond is not a canned response. Try to put some thought into it.

In my last post I talked about how you can restore the last visible section of the Hub. In that post I talked about the lack of the SelectedIndex and SelectedItem properties in the Hub control. These properties were in the Panorama control. Not having these properties means setting the visible section from a view model requires access to the Hub. This is not ideal. When functionality is not available, create it!

When you want to add functionality to a control there are two basic solutions.

Extend the control by creating a new one.

Extend the control with attached properties

The first solution is generally accomplished by inheriting from the control itself. The second is most often solved with a behavior. Whenever possible I prefer option 1 over option 2. The downside to option 1 is adding more and more functionality trying to come up with a good name for your control.

Extending existing controls is really easy. There [usually] is not a need to create a new style for the control. We can easily add new dependency properties to the control.

publicclass SelectionHub : Hub

{

publicint SelectedIndex

{

get { return (int)GetValue(SelectedIndexProperty); }

set { SetValue(SelectedIndexProperty, value); }

}

// Using a DependencyProperty as the backing store for SelectedIndex. This enables animation, styling, binding, etc...

When extending a control, you’ll want to override the OnApplyTemplate method to plug in your custom functionality. For adding the ability to add set or get the functionality, we’ll want to listen to when the section changes. In the last post I described how you can use the SelectionsInViewChanged event to be notified when the visible sections change. An odd thing about this event that Atley Hunter found is that it will not fire when the Hub has two sections. If we want a solution to work for all hubs, we need another event to hook into. If we view the style of the Hub control, we’ll see that is has a ScrollViewer control that aids moving content.

The ScrollViewer has the ViewChanged event that we can hook into to tell when the visible section changes! In the event we can what the current selected index is by checking the first index of the SectionsIdView list.

When the SelectedIndex changes, we want to set the visible section. The SelectedIndex can change from binding, from code behind, or from the user swiping. the _settingIndex property above is to prevent trying to change the visible section when setting the SelectedIndex when swiping.

The behavior listens to the loaded event of the hub because it is possible that the hub it attached after the hub has loaded or before. 99% of the time, it will be before the hub had loaded, but you never know. From there it is pretty much the same.

You can download a Universal app solution in which the Windows Phone project uses the behavior and the Windows project uses the new control. Either solution can be used, the choice of which was used for the the project was random.

For subsequent visits to the same hub control, take the user back to the section where they left off.

You can see this experience in the People hub.

In the Panorama control you could get the current visible item through either the SelectedIndex or the SelectedItem property, or be notified when the visible item changes with the SelectionChanged event. Following the guideline was a little hard however because the best way to ensure the pano opened to the correct page is with the DefaultItem property. The reason this was hard is because this excepts a PanoramoItem rather than an index. With an index, it could easily be saved and retrieved. With an item, it’s a little harder to save this information off and then get it the next time the app opened. While this was difficult, it was still doable.

The Hub control keeps this same workflow but has made an improvement. Instead of setting a default item, you now set an index with the DefaultSectionIndex property. The downside is the Hub control does not have a SelectedIndex or SelectedItem property. Fear not! The cheese was not removed, just moved. You can get the currently visible section with the SectionsInView property. This property returns an IList<HubSection> in which the first item in the list is the visible section and the second item in the list is the section that is peeking in on the right. With the SectionsInView and the Sections property, you can get the currently selected index.

var section = hub.SectionsInView[0];

var selectedIndex = hub.Sections.IndexOf(section);

Now that you have the visible section, you can save that off whenever you need to navigate away from your hub page. This can be done when navigating to a new page, or when the exiting the app. The hub even fires an event when the sections in view change.

Outlook.com offers the ability to add rules to your inbound traffic to help filter your mail. If you are part of a mailing list that gets a lot of emails, you may want to take advantage of these rules. Adding a rule to put these emails into a separate folder will help reduce “clutter” from your inbox folder. To accomplish this go to the settings of outlook.com and click Manage rules

From there click the New button, that will bring up the create rule page. Create a new rule when the email is sent to the mailing list.

Select a new folder for the mail to go into.

Click Save and from then on any mail to the mailing list will go to that folder!

With every major version of Windows Phone comes a new way to work with maps. Keeping up with all of these changes has, honestly, been a hassle. Windows Phone 8.1 continues this trend with the new MapControl. It does improve from Windows Phone 8 in a lot of ways. One of those areas is that you no longer need another toolkit to perform basic map functionality. In Windows Phone 8 you needed the Windows Phone Toolkit to do things like add map elements to the map. Now this functionality is part of the core functionality.

To bind a collection of items to the new MapControl you use the MapItemsControl within the MapControl itself.

<maps:MapControlx:Name="Map"MapServiceToken="abcdef-abcdefghijklmno">

<maps:MapItemsControlItemsSource="{Binding Locations}">

</maps:MapItemsControl>

</maps:MapControl>

The MapItemsControl is just a DependencyObject that has the ability to set items, through the Items and ItemsSource properties, and define what they look like with the ItemTemplate property. With the MapItemsControl ItemTemplate you can set your map icons to anything you want! Any XAML can be placed on your map!

This will put map icons on your map, but will not place them where they need to be (unlike the images I provided). To set the map location of the icons, you use the attached Location property on the MapControl.

<maps:MapItemsControl.ItemTemplate>

<DataTemplate>

<ImageSource="Assets/mappin.png"Height="25"

maps:MapControl.Location="{Binding Geopoint}"/>

</DataTemplate>

</maps:MapItemsControl.ItemTemplate>

This example assumes that the object you are binding to has a Geopoint property that returns a Geopoint. When map icons are placed, they are anchored at the top left of the icon. This works well if you use an icon that points to the top left, otherwise you will want to change it. To change the anchor point of the icon, you set the NormalizedAnchorPoint attached property on the MapControl. Set this with a Point with values between 0 and 1. Where 0,0 is the top left and 1,1 is the bottom right.

<maps:MapItemsControl.ItemTemplate>

<DataTemplate>

<ImageSource="Assets/mappin.png"Height="25"

maps:MapControl.Location="{Binding Geopoint}"

maps:MapControl.NormalizedAnchorPoint=".5,1"/>

</DataTemplate>

</maps:MapItemsControl.ItemTemplate>

Here is a weird bug that I swear was not there when I started working with the new maps back in May. Fellow MVP and mapping addict, Joost van Schaik, noticed that setting this value in xaml does nothing. It will always be anchored at the top left. He found that if you bind to an Anchor property then it works well.

<maps:MapItemsControl.ItemTemplate>

<DataTemplate>

<ImageSource="Assets/mappin.png"Height="25"

maps:MapControl.Location="{Binding Geopoint}"

maps:MapControl.NormalizedAnchorPoint="{Binding Anchor}"/>

</DataTemplate>

</maps:MapItemsControl.ItemTemplate>

Hopes this helps get you going with the new maps in Windows Phone 8.1. You can download a sample projectsample project to test as well.

An awesome part of Windows Phone and Windows Store apps is the ability to offer a trial version to users before they decide to purchase the app. This gives uses an opportunity to try the app for free before paying. There are different ways to offer trials. You can limit functionality while in trial mode. You can offer unlimited trials, allowing the user to use the app forever, or you can allow the user to use the app for limited time period. For Windows Store apps, you can specify in the Store how long the user is allowed to try the app.

Windows Phone apps do not offer this capability. When implementing timed trials in apps, a common task for app developers is to store a value within the app for when the app was first opened.

Note: As this is relevant for both Silverlight and Runtime apps, this blog will contain code for both. The code samples will switch back and forth.

publicstaticbool IsTrialExpired()

{

// Silverlight example

var appSettings = IsolatedStorageSettings.ApplicationSettings;

DateTime expirationDate;

if (appSettings.TryGetValue("TrialExpirationDate", out expirationDate) == false)

{

// first time app opened

expirationDate = DateTime.Now + TimeSpan.FromDays(7);

appSettings["TrialExpirationDate"] = expirationDate;

appSettings.Save();

}

return expirationDate > DateTime.Now;

}

You would then use this method along with the LicenseInformation class.

// Silverlight apps

var licenseInfo = new LicenseInformation();

var isTrial = licenseInfo.IsTrial();

// Runtime apps

var licenseInfo = CurrentApp.LicenseInformation

var isTrial = licenseInfo.IsTrial;

if(isTrial)

{

if(IsTrialExpired())

{

// tell user they can no longer use app

}

// possibly limit some functionality

}

This has been the solution for many apps. The problem with this solution is that the user can uninstall the app and reinstall and get the trial all over again! To overcome this, your app needs to use a service to store user information and check that service for if the trial has expired. There are many cloud based services available to you that are perfect for storing information like this. Two great services are Parse and Azure Mobile Services. This blog post will cover using Azure Mobile Services.

Using a service allows your app to check if the user opened the app at any time. If the user uninstalls the app and reinstalls it, they will now be able to get the trial again. The first step is to set up a mobile service in Azure.

Give the service a name. Name the service something that matches your apps name. If you do not already have a database in azure, create a new free db

When the service is created, click on it, then the Data tab and add new table

Give the table a name that maps to the app itself. This table will be in a database that you will use across multiple apps, so you don’t want something generic like UserInfo, or TrialUser.

Now for some code. First we will create a class that will represent our new table in Azure Mobile Services.

class MyAppUserInfo

{

publicstring Id { get; set; }

public DateTimeOffset TrialExpirationDate { get; set; }

}

Next let’s create a new interface and class that will allow us to check the service if the users trial has expired.

interface ITrialService

{

/// <summary>

/// Get or sets the amount of time the user is allowed to use the trial.

/// </summary>

TimeSpan TrialPeriod { get; set; }

/// <summary>

/// Gets a value indicating if the trial has expired for the given userId.

/// </summary>

/// <param name="userId">A unique idenitfier for a user</param>

/// <returns>A task that will complete when the data is retrieved.</returns>

Task<bool> IsExpired(string userId);

}

The interface is pretty simple. One property to specify how long the trial should last and one method to see if the trial has expired. For the class, the main this to implement it the IsExpiredAsync method.

Note: Ensure that you add the WindowsAzure.MobileServices nuget package.

So the IsExpiredAsync method will check Azure Mobile Services for the given userId. If none is returned, it will add a new user. Every time after that it will check the expiration date with the current time.

This current implementation is dependent on the MyAppUserInfo class, which means that we cannot reuse this class for multiple apps. I lie to reuse my code rather than copy and pasting code. Let’s make a modification to the interface and class that allows this to be used for any app.

First we’ll create an abstract class for the user information. We need an abstract class because I was not able to get data from the service using an interface. Might be user error, or an issue with the SDK. Our MyAppUserInfo will implement this abstract class.

/// <summary>

/// Represents information for a trial user.

/// </summary>

abstractclass TrialUser

{

/// <summary>

/// Gets or sets the id for the user.

/// </summary>

publicabstractstring Id { get; set; }

/// <summary>

/// Gets or sets the date the trial will expire for the user.

/// </summary>

publicabstract DateTimeOffset TrialExpirationDate { get; set; }

}

Next we will modify the IsExpiredAsync method to allow for a generic parameter, but must be of type ITrialUser

Now we have a service that can be used across multiple apps to test if a trial has expired for a user. Let’s take a step back for a moment. Our initial goal here was to stop storing trial expiration locally and start using a service. Check! This new service does accomplish that, but now it checks the service every time the app is opened. There is no need to delay the opening of the app any more than is needed. We can get the expiration information the first time the app is opened and save it to use on later opens. We’ll again modify the IsExpiredAsync method

Now when the user opens the app the second time, they will not hit the service. If they uninstall the app and reinstall, it will check the service once.

The TrialService does still rely on the date the user has on their phone. So there are two possible problems. The first is if the user sets the date ahead when they first open the app. The second is if they set the date back before opening the app. While this is probably not likely, you can prevent this if you wish.

To ensure the expiration date cannot be tampered we can set the date in the service script when a new row is created. Go to your mobile service in the Azure portal and select the Data tab and select your table. Select the Script tab and edit the insert script.

function insert(item, user, request) {

var today = new Date();

var expiration = new Date(today.setDate(today.getDate() + 7));

item.TrialExpirationDate = expiration;

request.execute();

}

This script will set the expiration date to be one week after the row is created.

Next select the read script. We will check the expiration when getting the user information.

function read(query, user, request) {

request.execute({

success: function(results) {

results.forEach(function(r) {

// IMPORTANT: Note the case of trialexpirationdate

r.isExpired = r.trialexpirationdate < new Date();

});

request.respond();

}

});

}

If you take this approach, you will need a new IsExpired property on your user info class and you can then remove the TrialExpirationDate property. You can also remove the TrialPeriod property from ITrialService since the period is being set on the server.

So now we have a way to get if the trial has expired, how do we get the id for the user? For Silverlight apps (Windows Phone 8) you can get the the anonymous id for a user through the UserExtendedProperties class.

string userId = UserExtendedProperties.GetValue("ANID2") asstring;

For Windows Phone 8.1 Runtime apps, there is no such property (that I have found!). I have seen some posts about using various device ids that are available, but this would mean the user could try the app on a number of devices. So far the best approach I have seen is from Dave Smits on the msdn forums. The solution is to use roaming settings to store a new unique ID.

object userId;

if (ApplicationData.Current.RoamingSettings.Values.TryGetValue("MyAppUserID", out userId) == false)

This TrialService should still be used along with the LicenseInfomation class to first check if the user is using the trial version of the app. You can get the complete code for the service on github.

It's important to also note that all records in Azure Mobile Services have a __createdAt column that can be used as well. You can get the property in your class by adding a JsonPropertyAttribute to a property with the name "__createdAt".