Cimbalino Toolkit 2.5.0

Yesterday I released Cimbalino Toolkit version 2.5.0!

Here’s what’s changed on this version:

  • Cimbalino.Toolkit.Core now targets the .NET Standard 1.0
  • Cimbalino.Toolkit.Core will now behave as the rest of the toolkit in regards to throwing NotImplementedExceptions only on specific cases
  • Exposed overrideable async methods in ExtendedPageBase
  • Other fixes and improvements

From the above, I’d like to emphasise the huge advantage of supporting .NET Standard 1.0: this means you can now use Cimbalino.Tookit.Core in all .NET platforms: .NET Framework, .NET Core, and Mono!

CultureInfo changes in UWP - Part 2

A while back I wrote an article about the CultureInfo changes in UWP and how they affected the UWP apps.

Well, things haven’t changed much since then, and the information in that article still stands today!

However, Microsoft has since open-sourced the .NET Core Runtime (CoreRT), and that allowed me to take a peek under the hood to understand what is going on.

While looking at the CultureInfo.cs code, I noticed the following comment on the CurrentCulture property:

We use the following order to return CurrentCulture and CurrentUICulture

  • Use WinRT to return the current user profile language
  • Use current thread culture if the user already set one using CurrentCulture/CurrentUICulture
  • Use thread culture if the user already set one using DefaultThreadCurrentCulture or DefaultThreadCurrentUICulture
  • Use NLS default user culture
  • Use NLS default system culture
  • Use Invariant culture

This confirms our findings!

Looking on the CultureInfo.Windows.cs partial class, I noticed the #if ENABLE_WINRT on the top, which forces the first rule on that comment!

Further down in the same file, we find a GetUserDefaultCulture method which uses the GetLocaleInfoEx Win32 API to retrieve the locale name.

This Win32 API is actually allowed for apps published to the Windows Store!

Retrieving the “proper” CurrentCulture, the proper way!

In my previous article on this subject, I found a hack where one could retrieve the “proper” CurrentCulture using the DateTimeFormatter class.

But with all this new information, I have now created a non-hacky way of doing the same:

using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

public class CultureInfoHelper
{
    [DllImport("api-ms-win-core-localization-l1-2-0.dll", CharSet = CharSet.Unicode)]
    private static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, StringBuilder lpLCData, int cchData);

    private const uint LOCALE_SNAME = 0x0000005c;
    private const string LOCALE_NAME_USER_DEFAULT = null;
    private const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale";

    private const int BUFFER_SIZE = 530;

    public static CultureInfo GetCurrentCulture()
    {
        var name = InvokeGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME);

        if (name == null)
        {
            name = InvokeGetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SNAME);

            if (name == null)
            {
                // If system default doesn't work, use invariant
                return CultureInfo.InvariantCulture;
            }
        }

        return new CultureInfo(name);
    }

    private static string InvokeGetLocaleInfoEx(string lpLocaleName, uint LCType)
    {
        var buffer = new StringBuilder(BUFFER_SIZE);

        var resultCode = GetLocaleInfoEx(lpLocaleName, LCType, buffer, BUFFER_SIZE);

        if (resultCode > 0)
        {
            return buffer.ToString();
        }

        return null;
    }
}

All you need is to copy the above to a file in your UWP project, and then call CultureInfoHelper.GetCurrentCulture().

I strongly advise using this new method instead of the “hack” I used in my previous article, as this is the same one that the .NET Framework relies on to retrieve the CurrentCulture information!

Creating custom build configurations for the .NET Core project format

MSBuild based projects have two default build configurations: Debug and Release.

While these two configurations are enough for most projects, some might actually require custom build configurations that will support different environments, alternative build targets, etc..

Until now we could use Visual Studio Configuration Manager to easily create a copy an existing configuration setup, and then change small bits to match our specifications.

But now there’s a new csproj format for .NET Core, and while it includes the expected Debug and Release build configurations, the “copy configuration” process doesn’t work anymore!

The problem is that the new project format is based in quite a few implicit defaults, so Visual Studio Configuration Manager can’t actually create a copy of the existing build configurations with all the properties set.

Introducing the MSBuild Configuration Defaults

As I couldn’t find a way to “inherit” from the base Debug and Release build configurations, I tried to understand what properties were actually required on each of them, and then create some build scripts that would set them for me!

Those MSBuild scripts are available here and can easily be installed by running Install-Package MSBuildConfigurationDefaults on the Package Manager Console, or added with the Visual Studio NuGet Packages Manager.

After adding the NuGet package, I recommend closing and re-opening the solution to ensure that the build scripts are correctly loaded.

Usage

Once installed, any custom build configuration name starting or ending on “Debug” will have the following build properties set by default:

<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>

Similarly, any custom build configuration name starting or ending on “Release” will have the following build properties set by default:

<DefineConstants>$(DefineConstants);RELEASE;TRACE</DefineConstants>
<DebugSymbols>false</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>

If any of these properties are set on the project, those values will have override the defaults above.

If you don’t want to name your custom build definition according to the rules above, just add a ConfigurationGroup property and set the value to Debug or Release to ensure those build definitions get the appropriate default properties set.

The following is an example of a custom build configuration called “Production”, that has the ConfigurationGroup set to “Release” (so it gets the default property values set as for the a “Release” build configuration), but also overrides the DebugSymbols property default value:

<PropertyGroup Condition="'$(Configuration)' == 'Production'">
  <ConfigurationGroup>Release</ConfigurationGroup>
  <DebugSymbols>true</DebugSymbols>
</PropertyGroup>

Await your event handlers completion with Deferred Events

Developers should avoid async void methods, but there are some situations where this is a “necessary evil”, and event handlers are one of those cases.

If one needs to use the await keyword inside an event handler code, the method itself must be async void

The following is an example of this:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        InitializeComponent();

        Loaded += MainPage_Loaded;
    }

    private async void MainPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        await DoSomethingAsync();

        await DoSomethingMoreAsync();
    }
}

On the above example, the MainPage_Loaded is an async void method that will as it needs to await for the completion of some of its calls, but sometimes we also need to allow the event invoker to wait for all handlers to complete.

Inspired on how the background tasks use a deferral approach to solving this problem (as they too are void methods), I came up with a similar approach!

Introducing the Deferred Events

A “deferred event” is basically an event that allows the invoker to wait for the completion of all event handlers.

My personal implementation is available on the DeferredEvents NuGet package that you can install by running Install-Package DeferredEvents on the Package Manager Console, or add with Visual Studio NuGet Packages Manager.

This is a .NET Standard 1.0 package, so you should be able to use it on any .NET project!

If you want to take a look at what’s inside, the full source code is available here.

Usage

Here is an example of a deferred event:

public event EventHandler<DeferredEventArgs> MyEvent;

The only difference here to a regular event is that the event arguments have to be of type DeferredEventArgs (or a custom class inheriting from them), and that’s what allows the whole thing to work!

Now take a look at how we raise this event:

await MyEvent.InvokeAsync(sender, DeferredEventArgs.Empty);

The InvokeAsync() is an extension method that will wait for all event handlers to finish their work before we proceed.

And finally, here’s how our event handler looks like:

public async void OnMyEvent(object sender, DeferredEventArgs e)
{
    var deferral = e.GetDeferral();

    await DoSomethingAsync();

    deferral.Complete();
}

The trick here is to call e.GetDeferral() to retrieve a deferral object, and just before we exit the method, we do deferral.Complete() to notify the invoker that we have completed our work!

There are a few rules that you have to be aware of:

  • You only need to call e.GetDeferral() if you actually want to the event caller to wait for the completion of the event handler; if you don’t call it, it will just behave as a regular event handler.
  • You must call e.GetDeferral() to get an EventDeferral instance before any await call in your code to ensure that the event caller knows that it should wait for deferral.Complete(); ideally, it should be the first thing you do in the event handler code.
  • If you have indeed called e.GetDeferral(), then you must call deferral.Complete() to signal that the event handler has finished.

To ensure the correct usage of the deferred events, use the following as a template for your event handlers:

public async void OnMyEvent(object sender, DeferredEventArgs e)
{
    var deferral = e.GetDeferral();

    try
    {
        // awaiteable code
    }
    finally
    {
        deferral.Complete();
    }
}

Alternatively, you can also use the using pattern like this:

public async void OnMyEvent(object sender, DeferredEventArgs e)
{
    using (e.GetDeferral())
    {
        // awaiteable code
    }
}

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!