Visually Located

XAML and GIS

Registering to any DependencyProperty changing in Windows 10 Apps

Many have argued that there are pieces still missing from Windows Runtime XAML that were in WPF. One item that was in WPF was the ability to be notified when a DependencyProperty changed. This functionality is now available in Windows Apps thanks to the new RegisterProperrtyChangedCallback method on DependencyObject. This opens up a world of opportunities for us. This functionality is extremely useful when creating custom controls or wrapping existing controls.

Rather than getting into anything complex, I’ll show a quick sample. A TextBlock control has Text, but no way to be notified when the text changes. We do have the ability to bind to the Text, but we’ll ignore that for now.

We’ll create two TextBlocks and one Button.

<StackPanel>
    <TextBlock x:Name="CounterText"/>
    <Button Content="Click me" Click="OnButtonClicked"/>
    <TextBlock x:Name="DuplicateTextBlock"/>
</StackPanel>

When the button is clicked we’ll set the text for the first TextBlock.

private int _counter;
 
private void OnButtonClicked(object sender, RoutedEventArgs e)
{
    CounterText.Text = string.Format("Clicked {0} times", ++_counter);
}

We’ll also register a callback for when the Text property changes for the CounterText TextBlock. Within the callback we’ll set the text of the other TextBlock.

public MainPage()
{
    this.InitializeComponent();
 
    CounterText.RegisterPropertyChangedCallback(TextBlock.TextProperty, OnTextChanged);
}
 
private void OnTextChanged(DependencyObject sender, DependencyProperty dp)
{
    var t = (TextBlock)sender;
 
    DuplicateTextBlock.Text = t.Text;
}

Now every time you click the button, it will set the text of the first TextBlock and the callback will fire setting the text of the second TextBlock!

capture-2

The benefit of an AdDuplex campaign

I recently had the opportunity to give 11 lucky winners $200 in AdDuplex credits. They are allowed to use these credits for anything they want. I wanted to highlight the benefits of using those credits for a campaign.

Last year I wanted to boost the downloads of my app 1:Clock. I decided to try a campaign through AdDuplex. I invested in a campaign for about three weeks. During that time I stopped and started the campaign. I targeted different country options and varied the amount of impressions. Overall I was very happy with the number of downloads I got during this period.

downloads

The timelines are as follows

  1. Started the campaign
  2. US market focus only
  3. Worldwide market focus
  4. Lower impression amount
  5. Raise impression amount
  6. Campaign ended

After the campaign ended my downloads were a little higher than before but did not maintain the download count I saw during the campaign. I did get quite a few reviews during this time which really helped out the app going forward! If you have some marketing budget, I would suggest trying out AdDuplex.

Enabling and tracking location in Windows Apps

Not much has changed with location in Windows Apps. You still use a Geolocator and still subscribe to the PositionChanged event or get one time location with the GetPositionAsync method. However I had problems getting started with a new Windows 10 project. I subscribed to the PositionChanged event, but it never fired. I subscribed to the StatusChanged event and found location was disabled. I was originally testing on the phone emulator and found that phone apps accessing location will now prompt the user.

So the phone prompted me for access, why is location disabled? Turns out you still need to add the location capability to your manifest file. There is not yet a GUI editor for the manifest file, so you must edit it manually. In the Capabilities element, add the following:

<DeviceCapability Name="location" />
Now run the app and you will have location data streaming in!

If you are running your app on a desktop or tablet, you will NOT be prompted for location access within the device capability. This removes some of the confusion. Hopefully this behavior will be consistent come RTM.

Creating a WrapPanel for your Windows Runtime apps

Recently I saw a friend, Glenn Versweyveld, write a blog about showing a “tags” (eg blog tags) within an app. The blog documents how to create a horizontal list of tags that are not formed into columns and rows. The list would let the items flow naturally. He used something I never would have thought of to accomplish this. He used a RichTextBlock. This was a rather cool idea that again, I would have never thought of.

When I saw the blog I quickly asked why he did not just use a GridView or a WrapGrid/ItemsWrapGrid. His simple reply was that it did not accomplish what he wanted due to the row/column layout.. 

If you are on “Big Windows” the GridView lays items out into columns and rows, by filling up columns from left to right. If you are on Windows Phone the Grid View also lays items in rows and columns, but it fills up rows first instead of columns.

The right picture shows Big Windows and the left shows phone.

GridView-BigWindowsGridView-Phone

Ok, so GridView is out, how about a ListView and change the ItemsPanel to be an ItemsWrapGrid with Orientation set to Horizontal? Nope, same row/column layout with that as well. Okay, now I see why Glenn went a custom route.

I like “Plug-n-Play” solutions. I like custom controls that I can put into XAML w/o and custom work. So, while I think Glenn’s approach was rather cool, it’s just not Plug-n-Play. To accomplish this wrapping we don't need to create a custom control. We can create a new Panel that we can use for any ItemsControl.

public class WrapPanel : Panel
{
    // 
}

When creating custom panels, there are two methods you must override, MeasureOverride and ArrangeOverride. The MeasureOverride method is where the panel determines how much space it will take up. It does this by asking each element within it to measure itself and then it will return the final size. The ArrangeOverride method is where the panel takes the information from the MeasureOverride and then places each item at X and Y locations.

The MeasureOverride will find the Height of the panel and just assume that the Width is the width it is given.

protected override Size MeasureOverride(Size availableSize)
{
    // Just take up all of the width
    Size finalSize = new Size { Width = availableSize.Width };
 
    double x = 0;
    double rowHeight = 0d;
    foreach (var child in Children)
    {
        // Tell the child control to determine the size needed
        child.Measure(availableSize);
 
        x += child.DesiredSize.Width;
        if (x > availableSize.Width)
        {
            // this item will start the next row
            x = child.DesiredSize.Width;
 
            // adjust the height of the panel
            finalSize.Height += rowHeight;
            rowHeight = child.DesiredSize.Height;
        }
        else
        {
            // Get the tallest item
            rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
        }
    }
 
    // Just in case we only had one row
    if(finalSize.Height == 0)
    {
        finalSize.Height = rowHeight;
    }
    return finalSize;
}

The ArrangeOverride will place each item at the correct X and Y location based on the size of the elements.

protected override Size ArrangeOverride(Size finalSize)
{
    Rect finalRect = new Rect(0, 0, finalSize.Width, finalSize.Height);
 
    double rowHeight = 0;
    foreach (var child in Children)
    {
        if ((child.DesiredSize.Width + finalRect.X) > finalSize.Width)
        {
            // next row!
            finalRect.X = 0;
            finalRect.Y += rowHeight;
            rowHeight = 0;
        }
        // Place the item
        child.Arrange(finalRect);
 
        // adjust the location for the next items
        finalRect.X += child.DesiredSize.Width;
        rowHeight = Math.Max(child.DesiredSize.Height, rowHeight);
    }
    return finalSize;
}

This panel will now layout items from left to right and any content that doesn’t fit in the row will go to the next row.

Let’s test this out. First we’ll try using an ItemsControl

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <controls:WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Background="Red" MinWidth="0" MinHeight="0" Margin="0,0,6,0">
                <TextBlock Text="{Binding}" FontSize="20"/>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

We get the following layout in both Phone and Windows

WrapPanel-BigWindows

If you use a ListView or ListBox you will get a slightly different layout due to the style of the ListViewItem and ListBoxItem. I’ll let you decide how you want to style those.

Why does my ListView scroll to the top when navigating backwards?

I’ve seen a few people asking this question. They have a page which contains a ListView and when an item is selected it navigates to another page. When they navigate backwards the ListView is back up to the top again. This behavior is due to the NavigationCacheMode of the page. By default the page will not cache rendered content when navigating “forward”. So when you navigate back to the page it re-renders the content. When displaying content like a ListView this will cause it to show the top content.

navigation

As with most things, there are a few solutions to this problem. The most common solution is to set the NaivationCacheMode to Enabled or Required.

public ListPage()
{
    this.InitializeComponent();
 
    this.NavigationCacheMode = NavigationCacheMode.Required;
}

These options do the following:

Member Value Description
Disabled 0

The page is never cached and a new instance of the page is created on each visit.

Required 1

The page is cached and the cached instance is reused for every visit regardless of the cache size for the frame.

Enabled 2

The page is cached, but the cached instance is discarded when the size of the cache for the frame is exceeded.

With this property set for the page the page content will not re-render because the rendered state has been cached!

It does get a little annoying to set the property for every page. I like to use a base page class that contains all my navigation stuff and cache mode as well. This makes it much easier to do the basic stuff.

public class AppPage : Page
{
    public AppPage()
    {
        NavigationCacheMode = NavigationCacheMode.Enabled;
 
        // other stuff for navigation
    }
}
 
public partial class ListPage : AppPage
{
    ...
}

Unfortunately this is not a dependency property so you cannot create a base style that sets this property.

A second option is to use the ScrollIntoView method of the ListView. When your page loads, simply scroll your current item into view. This does have the drawback of not being at the exact same spot as before so I do recommend using the NavigationCacheMode.

Displaying HTML content in a TextBlock

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.

public abstract class Behavior<T> : Behavior where T : DependencyObject
{
    protected T AssociatedObject
    {
        get { return base.AssociatedObject as T; }
    }
 
    protected override void OnAttached()
    {
        base.OnAttached();
        if (this.AssociatedObject == null) throw new InvalidOperationException("AssociatedObject is not of the right type");
    }
}
 
public abstract class Behavior : DependencyObject, IBehavior
{
    public void Attach(DependencyObject associatedObject)
    {
        AssociatedObject = associatedObject;
        OnAttached();
    }
 
    public void Detach()
    {
        OnDetaching();
    }
 
    protected virtual void OnAttached() { }
 
    protected virtual void OnDetaching() { }
 
    protected DependencyObject AssociatedObject { get; set; }
 
    DependencyObject IBehavior.AssociatedObject
    {
        get { return this.AssociatedObject; }
    }
}

You can also get the base class here.

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.

public class HtmlTextBehavior : Behavior<TextBlock>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += OnAssociatedObjectLoaded;
        AssociatedObject.LayoutUpdated += OnAssociatedObjectLayoutUpdated;
    }
 
    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
        AssociatedObject.LayoutUpdated -= OnAssociatedObjectLayoutUpdated;
    }
 
    private void OnAssociatedObjectLayoutUpdated(object sender, object o)
    {
        UpdateText();
    }
 
    private void OnAssociatedObjectLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        UpdateText();
        AssociatedObject.Loaded -= OnAssociatedObjectLoaded;
    }
 
    private void UpdateText()
    {
        // TODO
    }
}

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.

private void 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.

/// <summary>
/// Traverses the XElement and adds text to the InlineCollection.
/// </summary>
/// <param name="element"></param>
/// <param name="inlines"></param>
private static void ParseText(XElement element, InlineCollection inlines)
{
    if (element == null) return;
 
    InlineCollection currentInlines = inlines;
    var elementName = element.Name.ToString().ToUpper();
    switch (elementName)
    {
        case ElementA:
            var link = new Hyperlink();
            inlines.Add(link);
            currentInlines = link.Inlines;
            break;
        case ElementB:
        case ElementStrong:
            var bold = new Bold();
            inlines.Add(bold);
            currentInlines = bold.Inlines;
            break;
        case ElementI:
        case ElementEm:
            var italic = new Italic();
            inlines.Add(italic);
            currentInlines = italic.Inlines;
            break;
        case ElementU:
            var underline = new Underline();
            inlines.Add(underline);
            currentInlines = underline.Inlines;
            break;
        case ElementBr:
            inlines.Add(new LineBreak());
            break;
        case ElementP:
            // 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>
/// <param name="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

<Grid.Resources>
    <local:SampleData x:Key="Data"/>
</Grid.Resources>
<ItemsControl ItemsSource="{Binding HtmlItems, Source={StaticResource Data}}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding}" FontSize="20" TextWrapping="Wrap">
                    <Interactivity:Interaction.Behaviors>
                        <local:HtmlTextBehavior />
                    </Interactivity:Interaction.Behaviors>
                </TextBlock>
                <Line X1="0" X2="400" Stroke="Red" StrokeThickness="3"></Line>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

For this I put a line at the bottom of each element so you can see where it stops.

RenderedResults

You can see the extra line breaks for the paragraph elements. This won’t render prefect html and once again while this will work for a webpage, it shouldn’t be used to render an entire webpage!

You can download a complete working Universal sample.

Using the new Ad Mediator control for Windows Phone

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

I’m not going to go over this topic except to say to follow the documentation online.

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.
    AdProviders
  • 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

Ad Mediator works great for Windows Phone Silverlight apps. For Windows Phone Runtime (XAML) apps, only three providers are supported.

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.

Color and font resources to build a brand for your app

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.

Color Palette:
Fonts:

Again, if you know of more resources, please add a comment below!

The power of responding to user reviews in the Windows Phone Store

I have been responding to user reviews since the day it went live for all publishers

This was my first response to a user, and it worked!

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

Review1

 

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

Review1-update

 

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.

review2

 

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.

review3

 

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.

no-response

 

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.

Check out the email that is sent to the user when you respond to them.

What is the email sent from responding to user reviews in the Windows Phone store?

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.

respond

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).

MyReview

When the review came into DevCenter I quickly replied.

myResponse

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

EmailResponse

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.

Check out the power of responding to user reviews.