Visually Located

XAML and GIS

Creating a behavior to capitalize text

Many apps get data that they show from services. These services generally have their data cased a certain way. If you want to navigate to a page to show data, you may want to have the title of the page be information from the service.

image

The title portion of the page tells the user that this is the profile for Shawn Kendrot. The text for “Shawn Kendrot” came from the service and is cased in Title Case. But if you wanted to follow design guidelines (which are not a requirement), you may want the name to be all upper case.

To accomplish this you have three options, convert the text when you download it, create a value converter, or create a behavior. The first is really not an option, because that means that you can no longer use that text for anything else. Value converters are nice, easy to use, and sometimes overused. Behaviors are nice because they can easily be used within the designer of Blend. If you are not familiar with Blend, you should find time to use it. It is the tool to use when designing your apps.

The thing I love about working with behaviors is that they have a reference to the DependencyObject that they are associate with. They expose this object through the AssociatedObject property. You define the type of the associated object through the generic parameter of the abstract Behavior class

public class ToUpperBehavior : Behavior<TextBlock>
{
}

The other thing I like about behaviors is that you define when they should do work. The Behavior class has two methods that you can override that allow you to specify when you want the behavior to capitalize text. The OnAttached method fires when the AssociatedObject has been attached. It allows you to subscribe to any events of the associated object, or to make any changes that are needed. The OnDetached method fires when the AssociatedObject is being detached. It allows you to unsubscribe from any events that you subscribed to.

protected override void OnAttached()
{
    base.OnAttached();
 
    AssociatedObject.Loaded += AssociatedObjectOnLoaded;
    AssociatedObject.LayoutUpdated += AssociatedObjectOnLayoutUpdated;
}
 
protected override void OnDetaching()
{
    if (AssociatedObject != null)
    {
        AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
        AssociatedObject.LayoutUpdated -= AssociatedObjectOnLayoutUpdated;
    }
    base.OnDetaching();
}

We’ll subscribe to the Loaded and the LayoutUpdated event of the TextBlock. If you already have the data downloaded, you should only need the Loaded event. If you still need to get the data, the LayoutUpdated event let’s us know when the data comes in. When we have text in the TextBlock, we want to unsubscribe from the LayoutUpdated event so we stop getting updates (assuming we don’t need them any more) and to ensure we don’t leak memory through the event.

private void AssociatedObjectOnLayoutUpdated(object sender, EventArgs eventArgs)
{
    UpdateText();
}
 
private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
    UpdateText();
    AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
}
 
private void UpdateText()
{
    if (AssociatedObject == null) return;
    if (string.IsNullOrEmpty(AssociatedObject.Text)) return;
 
    AssociatedObject.Text = AssociatedObject.Text.ToUpper();
    AssociatedObject.LayoutUpdated -= AssociatedObjectOnLayoutUpdated;
}

Now, we can drag and drop the behavior within Blend onto the title TextBlock.

image

And we end up with text that has been capitalized.

image

Increasing productivity with ScriptCS

I’ve been working a lot with ScriptCS lately. It’s amazing how productive you can be working with this tool. There are so many times in the past when I would spin up a new project (or reuse an existing one) to test out some algorithm or small piece of code. Usually these projects are console applications that spit out some information at various times. This was the approach I took to test the performance of some IEnumerable extension methods. Using ScriptCS, I am able to remove the need for the extra project file, perform a quick test and then continue on with my development.

Most of the standard namespaces are already included (System, System.Collections.Generic, System.Linq, System.Text, System.Threading.Tasks, System.IO), but there are times when you will need to include the namespace of the class you are using (example: System.Diagnostics.Process class).

image

You can add a using statement if you will be using the namespace a lot.

image

You can also reference your own assemblies.

image

You can build loops within the script.

image

You can even create classes.

image

The above examples can even be pasted into the console! Just make sure that starting { brackets are on the same line as the loop/class/etc.

When you want to extend it even more you can write Script Pack.

Increasing in app purchases in your Windows Phone apps

There are a few ways to increase the rate of in app purchases. One of these ways is to show a message prompt to the user explaining that an in app purchase is available and what the user can get from it. In a previous post I explained how to use Telerik’s RateApplicationReminder to increase reviews of your app. The RateApplicationReminder is great because it just works. No, really. No need for you to determine if you should show a reminder to rate the app. It handles all of the logic and it navigates the user to rate your app. Another benefit of the RateApplicationReminder is that it is built on a framework for showing reminders. This framework can be extended to create your own reminders.

The is a decent framework to build reminders on. It has one abstract method, GetDataFilePath. This is just a file name for the data that will be saved. It has two virtual methods that can be overridden, but the power is in the properties that it has

// Summary:
// Setting this property to True will display a checkbox in the reminder that
// will allow users to skip further notifications.
public bool AllowUsersToSkipFurtherReminders { get; set; }
//
// Summary:
// Gets or sets a value indicating whether further reminders will be skipped.
public bool AreFurtherRemindersSkipped { get; set; }
//
// Summary:
// Gets the last date when reminder was displayed.
public ReminderBase DateTime? LastReminderDisplayDate { get; }
//
// Summary:
// Gets the number of app runs after the last reminder was displayed.
public int NumberOfUsagesAfterLastReminder { get; internal set; }
//
// Summary:
// Gets the persisted data.
protected T PersistedData { get; }

These properties a big part of when and if you should show a reminder. The RateApplicationReminder has some additional properties that dictate how many times (or the time frame) the app should open before showing a reminder. These properties are great for an in app purchase reminder as well. We’ll start there for our reminder

/// <summary>
/// Gets or sets the number of application runs on which the reminders will be displayed.
/// </summary>
public int? RecurrencePerUsageCount { get; set; }
 
/// <summary>
/// Gets or sets the time period on which the reminders will be displayed.
/// </summary>
public TimeSpan? RecurrencePerTimePeriod { get; set; }
 
/// <summary>
/// Gets or sets the information that will be displayed in the message box.
/// </summary>
public MessageBoxInfoModel MessageBoxInfo { get; set; }

The MessageBoxInfo determines what text should be shown to the user when the reminder is shown.You’ll want to have some default values for this.

public InAppPurchaseReminder()
{
    MessageBoxInfo = new MessageBoxInfoModel
        {
            Buttons = MessageBoxButtons.YesNo,
            SkipFurtherRemindersMessage = "Do not show this reminder again",
            Title = "In App Purchase"
        };
}

The ReminderBase class has the method, ShowReminderMessage, to show the reminder. When this is called the reminder will be shown even if it should not be. To ensure that the reminder is only shown when it is suppose to, the RateApplicationReminder has a Notify method that you call instead. The Notify method is where it is determined if it should be shown or not.

/// <summary>
/// Notifies the user of the in app purchase.
/// </summary>
public void Notify()
{
    IncreaseUsageCount();
    if (ShouldShowReminder() == false) return;
 
    var args = new CancelEventArgs();
    OnShowing(args);
    if (args.Cancel) return;
 
    ShowReminderMessage(MessageBoxInfo);
}
 
private void IncreaseUsageCount()
{
    // If the reminder has been shown at least once, and we're tracking usage count
    if (LastReminderDisplayDate.HasValue && RecurrencePerUsageCount.HasValue &&
        RecurrencePerUsageCount.Value > 0)
    {
        PersistedData.NumberOfAppRunsAfterLastReminder++;
        SavePersistedData();
    }
}
 
private bool ShouldShowReminder()
{
    if (LastReminderDisplayDate.HasValue && AreFurtherRemindersSkipped) return false;
 
    // priorty on usage count, calculate first
    if (RecurrencePerUsageCount.HasValue)
    {
        var numUsage = LastReminderDisplayDate.HasValue
                           ? NumberOfUsagesAfterLastReminder
                           : ApplicationUsageHelper.ApplicationRunsCountTotal;
 
        if (numUsage >= RecurrencePerUsageCount) return true;
    }
    // if no usage count, or the value has not been met, try time period
    if (RecurrencePerTimePeriod.HasValue)
    {
        var timeSpan = DateTime.Now - (LastReminderDisplayDate.HasValue
                                           ? LastReminderDisplayDate.Value
                                           : ApplicationUsageHelper.InitialInstallationDate);
        if (timeSpan >= RecurrencePerTimePeriod.Value) return true;
    }
 
    return false;
}

The Notify method calls the OnShowing method to notify you code that the dialog is going to be shown. It also gives event listeners a chance to stop the reminder from showing. If everything works out well, it shows the dialog. Inside IncreaseUsageCount, we call the SavePersistedData method. This will save any information that is in the ReminderBaseDataModel that is part of the class. For this reminder, we incremented the NumberOfAppRunsAfterLastReminder property. When the SavePersistedData method is called, it calls into the GetDataFilePath so it knows where to write the file of information.

/// <summary>
/// Gets or sets the product ID for the reminder .
/// </summary>
public string ProductID { get; set; }
 
protected override string GetDataFilePath()
{
    if (ProductID == null)
        throw new InvalidOperationException("ProductID property not specified.");
 
    return string.Format("PurchaseReminder_{0}.xml", ProductID);
}

To save the file, we’ll use the product id of the in app purchase. This guarantees us a unique file name for the application. The last thing to do is to show the in app purchase to the user if they decide to hit the yes button. To do this we need to override the OnReminderMessageClosed method.

protected override async void OnReminderMessageClosed(ReminderClosedEventArgs args)
{
    base.OnReminderMessageClosed(args);
 
    if (args.MessageBoxEventArgs.Result != DialogResult.OK) return;
 
    // Show the in ap purchase to the user if they tapped the yes button
    try
    {
        await CurrentApp.RequestProductPurchaseAsync(ProductID, false);
 
        if (CurrentApp.LicenseInformation.ProductLicenses[ProductID].IsActive)
        {
            AreFurtherRemindersSkipped = true;
 
            // If the IAP is a durable do the following
            // CurrentApp.ReportProductFulfillment(ProductID);
 
           // TODO: Fire an event thgat states that the purchase was made.
        }
    }
    catch (Exception)
    {
    }
}

Using the reminder is pretty simple. Here is an example to remove ads.

var reminder = new InAppPurchaseReminder()
{
    AllowUsersToSkipFurtherReminders = true,
    ProductID = "RemoveAdProductID",
};
 
reminder.MessageBoxInfo.Content =
    "Did you know that you can remove the ads and help support this app? Would you like to remove the ads now?";
reminder.MessageBoxInfo.Title = "Remove ads?";
// show on every tenth open of the app
reminder.RecurrencePerUsageCount = 10;
reminder.Notify();

You can download the complete file here. Good luck!

Increasing app reviews with Telerik’s RateApplicationReminder

I have seen a few blog posts that explain how to prompt a user to rate your app after a few visits. These posts describe how to store a setting for how many times the app has been opened and whether the prompt has been shown. Some use a custom message box and some use the built in MessageBox. There have even been NuGet packages for this. I have to wonder, Why are you not using Telerik’s RateApplicationReminder? After all, if you do not have Telerik’s controls, you might be doing something wrong.

Telerik’s RateApplicationReminder is a great tool to have. It allows users to ignore further reminders. It allows you to specify if the reminder should not be shown any more if the user taps the yes button. The text it displays is fully customizable, including the buttons. It also allows you to show the reminder based on number of times the app has opened or days from the last reminder. Oh, and it helps increase app reviews.

The RateApplicationReminder is used in conjunction with the ApplicationUsageHelper. The ApplicationUsageHelper tracks how many times a user has opened the app on a certain version. It’s a simple tool to use, insert one line of cod in the Launching and Activated event of your Application.

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    ApplicationUsageHelper.Init("1.0.0");
}
 
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    ApplicationUsageHelper.OnApplicationActivated();
}

It is required to use the ApplicationUsageHelper. With this in place we can take advantage of RateApplicationReminder to prompt users to rate your app. When you create the reminder, specify how it should be shown (or not shown) based on user interaction and the content of the prompt.

var reminder = new RadRateApplicationReminder
    {
        // Show the checkbox to the user to not show again
        AllowUsersToSkipFurtherReminders = true,
        // Do not show again if they press yes
        SkipFurtherRemindersOnYesPressed = true
    };
reminder.MessageBoxInfo.Content = "Would you like to rate this awesome app?";

Once you specify how to handle user interaction, set when the reminder will be shown. You can specify to show the reminder by setting the RecurrencePerUsageCount property, the RecurrencePerTimePeriod property, or a combination of both. You never need to check if you should show the reminder. All you need to do is call the Notify method. Telerik handles if the reminder should be shown.

If the reminder has never been shown these properties are based on the number of times the app has been opened or when the app was first opened. These values of how many times and when the application was opened come from the ApplicationUsgaeHelper.

If the reminder has been shown, the RecurrencePerUsageCount property specifies how many times the Notify method should be called before the reminder is actually shown. The RecurrencePerTimePeriod property specifies a TimeSpan from the last time the reminder was shown. You can set both properties. When this happens the reminder will first see if the RecurrencePerUsageCount has been met, if it has not, it will then check if the time since the reminder was last shown is greater than sRecurrencePerTimePeriod.

I like to use both properties, but not at the same time. It’s possible that a user may open the app 10 times in a day and I do not want to prompt them all the time. To take advantage of both settings, I check if the reminder has been shown before. You can do this by checking the LastReminderDisplayDate. This is a nullable DateTime and will be null if the reminder has never been shown.

if (reminder.LastReminderDisplayDate.HasValue == false)
{
    // reminder has not been shown before, allow the APP to open five times
    // before showing the reminder
    reminder.RecurrencePerUsageCount = 5;
}
else
{
    // reminder has been shown, show once every three days
    reminder.RecurrencePerTimePeriod = TimeSpan.FromDays(3);
}

In the snippet above I specify that the first time the reminder should be shown is when the app has been opened five times. Afterwards, it will open every three days. The following prompts from the reminder are only if the user taped the no button and has not checked the option to ignore future reminders. Remember, all of this is handled for you. The last thing to do is “show” the reminder.

// only shows the reminder when/if it is suppose to!
reminder.Notify();

Remember, no code to check how many time the app has been opened. No code to save/check if future reminders are disabled. You code is very simple. When we put all the snippets together we get the following

var reminder = new RadRateApplicationReminder
    {
        // Show the checkbox to the user to not show again
        AllowUsersToSkipFurtherReminders = true,
        // Do not show again if they press yes
        SkipFurtherRemindersOnYesPressed = true
    };
reminder.MessageBoxInfo.Content = "Would you like to rate this awesome app?";
 
if (reminder.LastReminderDisplayDate.HasValue == false)
{
    // reminder has not been shown before, allow the APP to open five times
    // before showing the reminder
    reminder.RecurrencePerUsageCount = 5;
}
else
{
    // reminder has been shown, show once every three days
    reminder.RecurrencePerTimePeriod = TimeSpan.FromDays(3);
}
 
// only shows the reminder when/if it is suppose to!
reminder.Notify();

Why do you not have Telerik's Phone controls for yours Windows Phone dev?

If you are doing Windows Phone development and you do NOT have Telerik’s Windows Phone control toolkit you are doing something wrong. For the price of a Windows Phone Store developer account (when not discounted) you can join Nokia’s Premium Developer Program. I have been in the program for almost a year and I’ll be renewing my subscription. The Premium Developer Program gives you the following:

  • A Windows Phone Dev Center  account (normally priced at $99, currently $19). You get a token for one year of membership to the dev center. This token can be used at any time. If you already have an account, you can use the token when the account expires.
  • A free license for Telerik RadControls for Windows Phone. These controls and tools are priced at $99 per year (if you wish to receive updates). I have found this toolset to be very valuable. I have only used a few of the components, but it has well passed the $99 value.
  • 12 months of access to Buddy.com. This cloud solution gives you one year of access to 1 million API calls per month. Buddy.com values this at up to $1200.
  • Two tech support tickets with Nokia. a $198 value.

I have not used Buddy.com, but when Parse offers the same plan for free, I cannot say you get much value from the offered plan from Buddy.com. I have yet to use the tech support tickets so no value there. The price for a dev center account is normally $99. They currently have an offer (ending in about a week) that lowers the price to $19. Being in the program did save me the normal $99 cost to renew my dev center account. That alone made the Premium Developer Program worth the cost. The real value for me is the Telerik RadControls license. I plan on doing some posts on a few of their controls that I have used. I can easily say that this toolset, along with the free Windows Phone Dev center account makes the Nokia Premium Developer Program well worth it.

This toolset is a must have for any Windows Phone developer.

Disclaimer: I am not, and was not paid by Telerik nor Nokia for this post (but I wouldn’t mind if I do :).

My first days with Xamarin iOS

I recently started a project in which I wanted to create an iOS app using Xamarin. This project will require me to create a binding to a third party iOS SDK, overcome a complex corporate network and prove to myself that Xmarin is a stable platform for development. I’ve only just begun this adventure, and I have already had a fare share of roadblocks to overcome. Here is a short description of the adventure that I chose.

I was very fortunate to talk with Xamarin while at the Microsoft Build conference in June. I was invited to a private dinner and was able to speak with Anuj Bhatia, Erik Polzin, and Xamarin’s own CEO and cofounder, Nat Friedman. Every one of them had heard of Schneider Electric and were excited to hear about how Xamarin could help us out. I’m glad that I also had Daniel Rouleau along with me as he has been helping lead up the development effort of our latest mobile platform.

I’ve done a bit of research on Mono/Xamarin before. I attended a Mono meetup at last years (2012) Build conference but never played around with it. After talking with these guys I was jazzed to start playing. I downloaded and installed Xamarin Studio and the Xamarin plugin for Visual Studio. Let’s me honest here. No one wants to use Xamarin Studio when they have been using Visual Studio for many years. Xamarin knows this and charges more (three times more) for their Visual Studio plugin. Building iOS apps on a Windows machine requires a Mac for compiling and deploying. Fortunately, my team recently got a new Mac Mini.

This Mac was still in it’s box, so I was able to do the unboxing and setup of the device.

Disclaimer: I’m not a Mac person. I’m not an iPhone person. The last time I used a Mac was in college when all of the PCs were already being used.

This Mac would be setup in a room and put on our “non corporate” network. We have a somewhat complex network at my work. We have two internal networks and domains. Anything corporate is within one network while anything we use/purchase is on another network. Communication between these is not ideal. The unboxing and setup was pretty smooth. I did need help from a fellow developer to download xCode from iTunes as I do not have an account.

The install of Xamarin on the Mac went pretty smooth by following the documentation although the docs do need some updated screen shots as it seems their installer has been updated. There were some confusing points like whether I needed to setup a proxy on the machine or not. After the installation on the Mac I went to my machine and attempted to connect to the build host (my Mac Mini) but it failed to connect.

image

Turns out that the Mac, like normal PCs, must have a static route configured to allow for communication between our two networks. Unlike Windows machines, you cannot easily configure a static route. You must create a script that gets run every time the machine boots up and then run that script. Once I did that (and entered the IP address rather than the machine name) I was able to access the machine!

image

I was able to successfully create and deploy Xamarin’s “HelloWorld” app as well as their “Master-Detail” app. My next steps are building out the bindings for the ArcGIS iOS SDK. If anyone out there already has something, please let me know.

Create a consistent background for your Panorama Title

I was helping out a fellow Windows Phone developer with some app testing today and noticed that his app had a Panorama control with a background color that had a break between the last page and the first page.

Here’s an example using the “Windows Phone Panorama App” project template.

image               image

This looks very weird and is distracting from the real content. This problem is very similar to the Changing the background color of your pivot headers post I did. You cannot just change the background within the TitleTemplate. The above images were created by modifying the TitleTemplate of the Panorama.

<controls:Panorama.TitleTemplate>
    <DataTemplate>
        <Border Background="Blue">
            <TextBlock Text="{Binding}" Width="800"
                       FontSize="80" Margin="0,75,0,0"/>
        </Border>
    </DataTemplate>
</controls:Panorama.TitleTemplate>

Note: The FontSize, Width and Margin were modified to make the title smaller.

Once again it’s Blend (or now VS2012!) to the rescue. Right click the Panorama and select Edit Template –> Edit a Copy… Much like the Pivot Header, the Panorama has a control for rendering the Title.

<controlsPrimitives:PanningTitleLayer x:Name="TitleLayer" CacheMode="BitmapCache" 
                                      ContentTemplate="{TemplateBinding TitleTemplate}" 
                                      Content="{TemplateBinding Title}" 
                                      FontSize="187" 
                                      FontFamily="{StaticResource PhoneFontFamilyLight}" 
                                      HorizontalAlignment="Left" 
                                      Margin="10,-76,0,9" 
                                      Grid.Row="0"/>

You could try setting the Background property of the PanningTitleLayer but will quickly find that it does nothing. You could modify the style of the PanningTitleLayer itself, but I find it is much easier to just add a Border immediately before the PanningTitleLayer.

<Border Background="Blue" Grid.Row="0"/>
<controlsPrimitives:PanningTitleLayer x:Name="TitleLayer" CacheMode="BitmapCache" 
                                      ContentTemplate="{TemplateBinding TitleTemplate}" 
                                      Content="{TemplateBinding Title}" 
                                      FontSize="187" 
                                      FontFamily="{StaticResource PhoneFontFamilyLight}" 
                                      HorizontalAlignment="Left" 
                                      Margin="10,-76,0,9" 
                                      Grid.Row="0"/>

Another option is to wrap the PanningTitleLayer with a Border control. With this new Border the background is consistent across all items of the Panorama.

image                 image

Using the new SettingsFlyout API in a Windows 8.1 AND Windows 8 Store app

Earlier today Ginny Caughey asked a question about how to maintain an app with support for Windows 8 and 8.1. It’s hard to answer a question that broad so I asked her what she wanted to take advantage of with 8.1. Her main use case is handling of screen [and app] sizes but while she was working, wanted to replace the Callisto SettingsFlyout control with the new native SettingsFlyout control in 8.1. I suggested a few ideas throughout the day from #if separation to MEF.

I started tonight working on a sample on how you could inject a SettingsFlyout using MEF but decided that it was just too complex for this example. I took a step back and thought about how to make this as easy as possible. I recently blogged about how to use the new Geolocator API within a Windows Phone 8 and Phone 7 application and thought that wrapping the Callisto API would be best suited for this situation as well.

The idea behind this blog is that you have one application that supports both Windows 8 and 8.1. You might do this because you want to start upgrading to 8.1 while still supporting Windows 8 (bug fixes, new features etc). to accomplish this you need to projects, one that targets 8 and one targeting 8.1. One project houses the files while the other adds the files as links.

The first step is to create a SettingsFlyout class. You want this class to be in the Windows.UI.Xaml.Controls namespace so that your app can use the same code. The new SettingsFlyout control has nine properties, three methods and one event that are specific to it. You may or may not need all of the properties/methods. Some are not supported in Callisto so while we can stub them, they will have no effect.

using Windows.UI.Xaml.Media;
 
namespace Windows.UI.Xaml.Controls
{
    public class SettingsFlyout
    {
        private readonly Callisto.Controls.SettingsFlyout _settings = new Callisto.Controls.SettingsFlyout();
 
        public Brush HeaderBackground
        {
            get { return _settings.HeaderBrush; }
            set { _settings.HeaderBrush = (SolidColorBrush)value; }
        }
 
        public string Title
        {
            get { return _settings.HeaderText; }
            set { _settings.HeaderText = value; }
        }
 
        public object Content
        {
            get { return _settings.Content; }
            set { _settings.Content = value; }
        }
 
        public ImageSource IconSource
        {
            get { return _settings.SmallLogoImageSource; }
            set { _settings.SmallLogoImageSource = value; }
        }
 
        public void Show()
        {
            _settings.IsOpen = true;
        }
 
        public void Hide()
        {
            _settings.IsOpen = false;
        }
    }
}

I only implemented a few of the properties/methods for this sample. If you need more it’s easy to add them. The biggest drawback of this implementation is that it can only be used through code. This does not work if you want to declare your SettingsFlyout in xaml. To create the SettingsFlyout in code subscribe to the Loaded event of the rootFrame within App.xaml.cs. Within the Laded event tell the app that you have settings.

private void RootFrameOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
    SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
}

Within the OnCommandsRequested event is where you build up your settings. Now that we have wrapped the Callisto SettingsFlyout, we can use the 8.1 API for creating one!

private void OnCommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
    var flyout = new Windows.UI.Xaml.Controls.SettingsFlyout
    {
        HeaderBackground = new SolidColorBrush(Colors.Blue)
    };
 
    args.Request.ApplicationCommands.Add(
        new SettingsCommand("MySettings", "General Settings",
        command =>
        {
            flyout.Title = "General Settings";
            // replace this content with a control that houses yor settings
            flyout.Content = new Rectangle 
                {Fill = new SolidColorBrush(Colors.Red), Width = 100, Height = 100};
            flyout.Show();
        }));
}

It’s as simple as that.

Remove ads with an in app purchase across your entire app

Today I read that the Windows Phone team had added some new samples. I was excited to take a look at the Free App With Paid Products sample to see if they had done anything different than I had in Disney Expedition. When looking at the sample I was even more excited to see this in MainPage.xaml.cs

// Each in-app product is identified by a string that is unique for the owning app. This value 
// is an example identifier for a product that causes the display of ads to be removed from the app. 
private const string PRODUCTID = "AdRemovalProductIdentifier"; 

This little snippet was exactly what I was doing! Using the In App Purchase(IAP) model to remove ads from my app. I continued to look at the sample only to become disappointed that the sample did not really show how to remove ads with an In App Purchase. Okay, I wasn’t that disappointed. Removing an ad on a single page once the purchase is made is easy enough to do if you follow the sample. But there are many unanswered questions

  • What if you have multiple pages with ads?
  • How do you give the option (button or menu item) to remove ads across many pages?
  • How do you remove/hide the ad for a new page if the purchase has been made?

When using IAP to remove ads you should give the user the ability to remove the ads on every page that has ads.

Note: Another option is to have a central location like settings to remove ads. I don’t like this option because often users don’t go to the settings.

The option you give users could be either a button on the ApplicationBar or a MenuItem. While a menu item is not as visible as a button you can be guaranteed that you will have room in the menu to put an option. The menu item should be visible if the IAP has not been made and be hidden if the purchase has been made. Often times you show/hide items with a BooleanToVisibilityValueConverter. Menu items do not have this ability so you’ll want to do this in code. A good place to do this is within the Loaded event of the PhoneApplicationPage. To make this code reusable it will be placed in a class called AdPhoneApplicationPage which inherits from PhoneApplicationPage. This allows you to make any page in your app an AdPhoneApplicationPage rather than a PhoneApplicationPage.

private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
    bool adsRemoved = App.AdsRemoved;
 
    // If there is not an ApplicationBar on this page we will need to add one
    if ((ApplicationBar == null) && (adsRemoved == false))
    {
        ApplicationBar = new ApplicationBar
            {
                // Minimize the bar as it will only have a menu item
                Mode = ApplicationBarMode.Minimized
 
               //TODO: Set Background/Foreground color to match your app theme
            };
    }
    // ApplicationBar is null and ads have been removed. Nothing to do!
    else if (ApplicationBar == null) return;
 
    ApplicationBarMenuItem removeAdMenuItem = null;
    if (ApplicationBar.MenuItems != null)
    {
        foreach (ApplicationBarMenuItem menuItem in ApplicationBar.MenuItems.OfType<ApplicationBarMenuItem>())
        {
            if (menuItem != null)
            {
                if (menuItem.Text == "remove ads")
                {
                    removeAdMenuItem = menuItem;
                    break;
                }
            }
        }
    }
 
    if ((removeAdMenuItem != null) && adsRemoved)
    {
        // Purchase has been made. Remove the option
        removeAdMenuItem.Click -= RemoveAdMenuItemOnClick;
        ApplicationBar.MenuItems.Remove(removeAdMenuItem);
 
        // TODO: Remove the ad
    }
    else if ((removeAdMenuItem == null) && (adsRemoved == false))
    {
        // Purchase has not been made, give them to option
        removeAdMenuItem = new ApplicationBarMenuItem("remove ads");
        removeAdMenuItem.Click += RemoveAdMenuItemOnClick;
        ApplicationBar.MenuItems.Add(removeAdMenuItem);
    }
}

The Loaded event will either add or remove the menu item to the ApplicationBar. If the page does not have an ApplicationBar one will be created to place the menu item in. If the purchase has been made the menu item will be removed. The AdsRemoved property is very similar to the one in the sample except that it caches the value of the purchase.

private static bool? _adsRemoved;
private bool AdsRemoved
{
    get
    {
        if (_adsRemoved == null)
        {
            _adsRemoved = CurrentApp.LicenseInformation.ProductLicenses["RemoveAdsProductID"].IsActive;
        }
        return _adsRemoved.Value;
    }
}

When the menu item is clicked, we’ll want to perform the IAP and if the user did complete the purchase, remove the menu item.

private async void RemoveAdMenuItemOnClick(object sender, EventArgs eventArgs)
{
    try
    {
        // prompt the user to purchase
        await CurrentApp.RequestProductPurchaseAsync("RemoveAdsProductID", false);
 
        if (CurrentApp.LicenseInformation.ProductLicenses["RemoveAdsProductID"].IsActive)
        {
            // we're rich!
            _adsRemoved = true;
 
            // Remove the menu item 
            var menuItem = (ApplicationBarMenuItem)sender;
            ApplicationBar.MenuItems.Remove(menuItem);
 
 
            // TODO: Remove ad
        }
    }
    catch (Exception)
    {
    }
}

Notice I had a TODO in there to remove the ad; after all, this is what we are intending to do. One option is to create a custom control that wraps the AdControl and hides it on load if the purchase has been made (I’ll blog about this awesomeness later). Another option is to traverse the child controls of the page to find the AdControl and hide it.

private bool RemoveAdControl(DependencyObject d)
{
    var adControl = d as Microsoft.Advertising.Mobile.UI.AdControl;
    if (adControl != null)
    {
        adControl.Visibility = Visibility.Collapsed;
        return true;
    }
 
    var childCount = VisualTreeHelper.GetChildrenCount(d);
    // start at the end of the children as the AdControl is likely to be at the bottom
    for (int i = childCount - 1; i >= 0; i--)
    {
        bool adRemoved = RemoveAdControl(VisualTreeHelper.GetChild(d, i));
        if (adRemoved) return true;
    }
    return false;
}

This simple method uses recursion to find the AdControl and hide it. Replace the TODO statements will one line of code.

RemoveAdControl(this);

You can download the entire AdPhoneApplicationPage here.

In case you do not know how to change the type of PhoneApplicationPage for your pages, here’s a little snippet

<localControls:AdPhoneApplicationPage
    x:Class="VisuallyLocated.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:VisuallyLocated.Controls">
 
<!-- content -->
 
</localControls:AdPhoneApplicationPage>
    

Make sure that your code behind then inherits from AdPhoneApplicationPage instead of PhoneApplicationPage.

We couldn’t get your developer license for Windows 8.1 Preview… SOLVED!

I’ve been trying to get going with developing Windows 8.1 Store apps on my new Surface Pro but was continually running into the following error.

It turns out this error is due to how I configure my PCs. Every time I build a new computer or install a version of Windows I create an “admin” account. This account is only used for admin related stuff. My normal account is not an admin account. I have been doing this configuration since XP due to the lack of security that XP originally offered.

I tried running Visual Studio 2013 as admin, I tried running powershell and the command “Show-WindowsDeveloperLicenseRegistration” but all failed. It wasn’t until a helpful Hermit Dave tried to diagnose this issue with me over twitter that I was able to solve it.

The solution is to log in as your admin account and either run the powershell command or VS2013 to get the developer account prompt, enter you Microsoft account information and then log back into your regular account.

Again, big thanks to Hermit Dave for the help on this issue.