Setting a custom User-Agent in the UWP WebView control

I recently came into a UWP project requiring all HTTP requests to use a specific User-Agent string.

That’s quite easy to do if you only use Windows.Web.Http.HttpClient as there’s a managed property for that purpose: HttpClient.DefaultRequestHeaders.UserAgent.

Similarly, the same applies for System.Net.Http.HttpClient and the HttpClient.DefaultHeader.UserAgent property.

The real problem is if you need to use the WebView control to present web content, as there’s no managed property to change the user-agent!

It is possible to create a HttpRequestMessage instance, set a custom user-agent string in it, and then call the WebView.NavigateWithHttpRequestMessage method, but that will only work for that specific navigation request.

Any requests invoked from inside the webview (like a form post) will use the system default user-agent string.

So what’s the solution?

The solution comes in the form of a Win32 API called UrlMkSetSessionOption.

Amongst other things, this API allows you to set the default user-agent string for the current internet session!

Here’s an example of how to use it; first, add the following class to your app:

public class UserAgentHelper
{
    [DllImport("urlmon.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
    private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);

    private const int URLMON_OPTION_USERAGENT = 0x10000001;

    public static void SetDefaultUserAgent(string userAgent)
    {
        UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, userAgent, userAgent.Length, 0);
    }
}

Now load your App.xaml.cs file and ensure you call the UserAgentHelper.SetDefaultUserAgent() method inside the App class constructor:

public App()
{
    // remaining code

    UserAgentHelper.SetDefaultUserAgent("MyApp/1.0");
}

From that point on, any webview inside your app will use the specified user-agent string (“MyApp/1.0” in our example above)!

One final note: only a few Win32 API’s are actually allowed in apps published to the Windows Store (you can check the complete list here)!

The Windows Store recently allowed for apps to use the UrlMkSetSessionOption API, but if you look at the list above you will notice that it’s not yet listed; that should change once Microsoft updates the list on that page.

Kudos to Hermit Dave for pointing me in the right direction for a solution for this problem!

Migrated from WordPress to Jekyll

For a long time now, my blog has been powered by WordPress and hosted on GoDaddy shared hosting.

Last week I noticed that the blog was down, and when I opened GoDaddy’s shared hosting administration area, I got a database connection error message.

I then did what anyone in this situation would do: get help!

However, contacting GoDaddy support proved completely useless, as all I got was something along the lines of “yes, there’s a problem and we’re working on to fix it; no, we don’t know when it’s gonna be fixed, so please try later”

After some 5 hours, the blog was back up and running… but there was a big problem: some content had disappeared!

I’m guessing they had some problem with the database server, and their “fix” involved recovering the databases from an old backup.

That was the final reason I needed to completely ditch WordPress and GoDaddy, and migrate to something faster and more recent: this blog is now fully powered by Jekyll and hosted in GitHub Pages!

Major advantages of this approach are:

  • No more MySQL or any other database server involved
  • full control over rendered content
  • everything is statically generated on every commit of the git repo, so it’s blazing fast!
  • I can host it for free in GitHub Pages and add some nice features like allowing other people to send me Pull Requests with fixes and improvements (or just to correct my recurrent typos!)

This right now is actually the first post I write in the new platform! :)

There are still a few quirks to fix, so if you find any problem please report it by creating a new issue and I’ll take care of it as soon as possible!

Awarded Microsoft Windows Development MVP 2017

It is with great pride that I received the Microsoft Most Valuable Professional (MVP) Award 2017 for Windows Development!

From the Microsoft MVP award overview page:

“…the Microsoft MVP Award is our way of saying “Thanks!” to outstanding community leaders.”

This is my first MVP Awards and to me feels like the top recognition for all the work I’ve been doing for the past few years with the community around Microsoft Technologies, particularly in Windows and Windows Phone development.

I consider this award as a personal achievement, but it is one that I could not have accomplished without the help and support of some people, specifically:

  • Scott Lovegrove, Joost van Schaik, Glenn Versweyveld, Hermit Dave, Sébastien Lachance, Bart Lannoeye, and quite a few other distinguished MVP’s!
  • Alberto Silva, Sandro Pereira, Tiago Pascoal, Paulo Morgado, and other fellow Portuguese MVP’s!
  • Luis Calado, João Pedro Martins, Clint Rutkas, and quite a few other Microsoft employees!
  • my wife, Joana, who has the patience to put up with me doing “geeky” stuff all the time!

…and finally but most importantly, the whole community, who reads my blog, follows me on twitter, checks my code contributions, downloads my apps, and gives me the opportunity to carry on doing what I’ve done so far and that will continue to improve in the future!

Thanks! :)

Adaptive Triggers failing? Better check your control names!

TL;DR

Adaptive triggers will not work if you are trying to change a control whose instance name is the same as one of the VisualStates of any control on the page, so make sure you name your controls accordingly!

The long run…

I recently came to discover what I believe to be a UWP platform bug related to how one names the instance controls and how these may collided with the VisualState names!

Let’s take the following sample code for a simple AdaptiveTrigger usage example:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="MyButton" Content="I don't do anything!" />

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup">
            <VisualState x:Name="VisualStateNarrow">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="MyButton.Background" Value="Red" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="VisualStateNormal">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="600" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="MyButton.Background" Value="Green" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

Here we can see we have a Button called “MyButton”, who’s background color will change accordingly to the window size: if the window width is above 600, the button will be green, and if it is below 600, it will be red.

Now here’s how it looks when we run the sample code:

Simple AdaptiveTrigger working

Works exactly as expected! :)

If you take a look at the Button styles and templates, you will find out that the Button control contains the following named VisualStates: “Normal”, “PointerOver”, “Pressed”, “Disabled”.

Given this information, let’s rename our button from “MyButton” to “Pressed”:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="Pressed" Content="I don't do anything!" />

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup">
            <VisualState x:Name="VisualStateNarrow">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="Pressed.Background" Value="Red" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="VisualStateNormal">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="600" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="Pressed.Background" Value="Green" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

This is the result if you run the code again:

AdaptiveTrigger now failing

What you see here is that the initial state was in fact applied, but it failed to change once we started to change the window size as it was supposed to!

Further testing made me aware that this is not only influenced by the visual states of the control we are manipulating, but by all controls on the page!

As an example of this, on the following code we have now added a ComboBox control, which will also fail the adaptive changes as I named our button Focused which matches one of the ComboBox visual states:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="Focused" Content="I don't do anything!" />
    <ComboBox />

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup">
            <VisualState x:Name="VisualStateNarrow">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="Focused.Background" Value="Red" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="VisualStateNormal">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="600" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="Focused.Background" Value="Green" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

I’ve reported this issue to Microsoft, so for now all we can do is to be aware of it and make sure we name our controls so not to use the same names as any of their visual states!

Cimbalino Toolkit 2.4.0

I know the blog as been quite a bit quiet for the last couple of months, but I just wanted to let you know that Cimbalino Toolkit version 2.4.0 is now available!

As I didn’t put a blog post for the previous version, here’s the complete change log for everything since 2.2.0 till the current 2.4.0:

  • Now targeting SDK 14393 (Windows 10 Anniversary edition)
  • New MasterDetailView control (UWP only)
  • New ExtendedPageBase class, IHandleNavigatingFrom, IHandleNavigatedFrom and IHandleNavigatedTo interfaces (allows handling of Page.OnNavigatingFrom(), Page.OnNavigatedFrom() and Page.OnNavigatedTo() methods from inside view models)
  • New BooleanToObjectConverter, CollectionCountToObjectConverter, ComparableToObjectConverter, EmptyCollectionToObjectConverter, and EmptyStringToObjectConverter
  • Added CancellationToken support to IMessageBoxService and ILocationService
  • HamburgerMenuButton will now allow parameter check for button highlighting
  • Improvements over the INavigationService interface and implementation
  • Other fixes and improvements

Changing the Raspberry Pi Touch Display Rotation in Windows 10 IoT

If you have a Raspberry Pi 3 running Windows 10 Core IoT and the 7” touch display, then this post is for you!

Assuming you already installed the Windows 10 IoT in your Pi 3 and that it is currently up and connected to the network, you can open the Windows 10 IoT Core Dashboard, go to the “My Devices” tab and find your device listed there.

If you now click the “Open in Device Portal” option, the browser will launch, ask you to login with your credentials, and then show you the “Home” page of the Device Portal.

On the bottom you will find the “Display Orientation” option:

Display Orientation setting in the Device Portal

Given my touch screen is placed upside down, I changed this setting to “Landscape (Flipped)”, and after rebooting the device I noticed that it flipped the touch screen display as requested, but it didn’t also flip the touch targets (so you’ll need to mentally rotate every point you touch on the screen to make it do what it is supposed to do)!

Under the hood, what this setting is doing is adding display_rotation=2 to the Raspberry Pi “config.txt” file, but that’s not the proper way of doing this for the touch screen!

After reading the Raspberry Pi Display troubleshooting, I realized that one should use lcd_rotate=2 instead, which will rotate the lcd display and touch targets!

So the fix is quite easy: just open the \\<your-pi-ip-address>\c$ network share, go to the “EFIESP” folder and inside of it, find and edit the “config.txt” file!

Remove any display_rodate entry and add lcd_rotate=2 to the end of the file, save, reboot the Pi, and that should fix the problem completely! :)

Cimbalino Toolkit 2.2.0

Update: there was a packaging error in 2.2.0 which I already fixed and so the most current version is now 2.2.1!

Cimbalino Toolkit version 2.2.0 is now available!

This new version includes improved support for Windows Phone Silverlight 8.1 (WP81) so that developers can take advantage of its specific API’s (such as the FileOpenPicker)

This brings the total number of supported platforms to 5:

  • Windows Phone Silverlight 8.0 apps (WP8)
  • Windows Phone Silverlight 8.1 apps (WP81)
  • Windows Phone 8.1 apps (WPA81)
  • Windows Store 8.1 apps (Win81)
  • Windows 10 UWP apps (UAP)

Here’s the full change log for version 2.0.0:

  • Improved compatibility with Windows Phone Silverlight 8.1 (WP81)
  • New Cimbalino.Toolkit.Controls library (includes the HamburgerFrame for Windows 10)
  • New IFilePickerService to handle the file picker (when available)
  • Improvements over the INavigationService implementation
  • Other fixes and improvements

Cimbalino Toolkit Hamburger controls for UWP

Like it or not, the so called “Hamburger” design pattern has made its way to pretty much every platform, including the Windows Universal Apps!

Most Windows 10 native apps already show this new pattern, even a classic like the Calculator app!

However, for reasons unknown, Microsoft didn’t provide any Hamburger related control on the SDK base controls… frankly, this move brings back to memory when Windows Phone 7 SDK was launched without the Panorama and Pivot controls, the foundation of the whole “Metro” design guidelines!

The only alternative I’ve found is to use the Template 10, a “set of Visual Studio project templates”!

However, I’ve found that Template 10 version for Hamburger adds a bit of too much “fat” for my own taste, hence why I’ve been working on an alternative for the past last few weeks!

Introducing the Cimbalino Toolkit Controls

Starting with version 2.2.0 (currently still in beta 1), the Cimbalino Toolkit will feature a new package called Cimbalino.Toolkit.Control, and as the name suggests, it’s a control library for app developers.

Currently, the package features 3 controls:

  • HamburgerFrame
  • HamburgerTitleBar
  • HamburgerMenuButton

HamburgerFrame

Starting from the top, the HamburgerFrame control is a full replacement for the native Frame root control used in the app.xaml.cs file.

The control provides 3 content containers represented by the Header, SubHeader, and Pane properties, and on the center, it will show the navigated content:

HamburgerFrame container thumb

Obviously, you can specify content for this containers however you would like, or just leave them blank!

The Header allows content to be presented above the Pane, so it will never be hidden by it:

HamburgerFrame container thumb

The SubHeader allows content to be presented on the right side of the Pane. This means that if the pane is in one of the “overflow” modes it will show on top of this container, hiding the content behind it:

HamburgerFrame container thumb

The control also provides background properties for all these containers (HeaderBackground, SubHeaderBackground, and PaneBackground).

To make the life easier of developers, I’ve “borrowed” the VisualStateNarrowMinWidth, VisualStateNormalMinWidth, and VisualStateWideMinWidth properties from Template 10, which allow to specify the break points where the pane state and location will readjust. If you don’t want to use these, you can always do it manually with the exposed pane related properties (IsPaneOpen, DisplayMode, OpenPaneLength, CompactPaneLength, …).

HamburgerTitleBar

The HamburgerTitleBar control provides a basic Hamburger button on the left side (can be hidden with the MenuButtonVisibility property), and a Title property.

HamburgerTitleBar

This is a quite rudimentar and easy to use control, yet developers might want to just go ahead and create their own version of this control and place it on their apps!

HamburgerMenuButton

Finally, the HamburgerMenuButton is the button you’ll be using in the pane to indicate the available menu options!

This control shows a left-side icon and an optional label (through the Icon and Content properties):

HamburgerMenuButton basic states

The regular approach here will be to just place all the HamburgerMenuButton controls inside a vertical StackPanel, but one can also stack them horizontally, and in this case, we would only show the icon and hide the label (using the provided LabelVisibility property).

The NavigationSourcePageType property allow developers to specify the destination page type for navigation purposes. If the property is set, the button will automatically highlight anytime the page is the frame current navigation content.

So how can I use these in my app?

First step is to add the Cimbalino.Toolkit.Controls NuGet package to the project!

Then, create a new user control to define your menu; in it, add as many HamburgerMenuButton instances as the number of options you want to present!

Here’s how your menu might look like:

<UserControl x:Class="App1.View.HamburgerPaneControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:controls="using:Cimbalino.Toolkit.Controls"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:view="using:App1.View"
             d:DesignHeight="300"
             d:DesignWidth="400"
             mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <StackPanel>
            <controls:HamburgerMenuButton Content="Home" NavigationSourcePageType="view:MainPage">
                <controls:HamburgerMenuButton.Icon>
                    <FontIcon FontSize="16" Glyph="& #xE80F;" />
                </controls:HamburgerMenuButton.Icon>
            </controls:HamburgerMenuButton>

            <controls:HamburgerMenuButton Content="Details" NavigationSourcePageType="view:DetailsPage">
                <controls:HamburgerMenuButton.Icon>
                    <FontIcon FontSize="16" Glyph="& #xE8BC;" />
                </controls:HamburgerMenuButton.Icon>
            </controls:HamburgerMenuButton>
        </StackPanel>

        <controls:HamburgerMenuButton Grid.Row="1"
                                  Content="Settings"
                                  NavigationSourcePageType="view:SettingsPage">
            <controls:HamburgerMenuButton.Icon>
                <FontIcon FontSize="16" Glyph="& #xE713;" />
            </controls:HamburgerMenuButton.Icon>
        </controls:HamburgerMenuButton>
    </Grid>
</UserControl>

Next, open the app.xaml.cs file and replace this line:

rootFrame = new Frame();

with this:

rootFrame = new Cimbalino.Toolkit.Controls.HamburgerFrame()
{
    Header = new Cimbalino.Toolkit.Controls.HamburgerTitleBar()
    {
        Title = "App1"
    },
    Pane = new View.HamburgerPaneControl()
}

Congratulation: your app now has a universal Hamburger menu with a nice title bar! :)

App with HamburgerFrame

Next steps might be to create a separate user control to hold the HamburgerTitleBar, which will then allow you to bind the Title property to view model (making it easier to update on a page by page basis).

To make things easier, I’ve provided the source code for a simple app using these controls!