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

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

Awaiting the CoreDispatcher

Most programming language allow you to take advantage of multi-threaded execution, and .NET is no exception!

Asynchronous code is a modern abstraction of multi-threading execution, and as you hopefully are aware, in .NET land, this is achieved with the async and await keywords.

For the Universal Windows Platform, we can also count on the CoreDispatcher class to marshal execution back to the main thread, from which we can update the UI of our apps.

Here’s a simple example of how to use it:

public async void DoStuff()
{
    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        UpdateUI();
    });

    DoOtherStuff();
}

Assuming we are on a background thread when the DoStuff() method is invoked, we will retrieve a CoreDispatcher instance from the CoreWindow.CoreDispatcher property, call and await for the execution of dispatcher.RunAsync() method, which in turn will invoke the UpdateUI() method on the main thread, and then code execution will continue in the background thread by invoking the DoOtherStuff() method.

As it is right now, we know that DoOtherStuff will only execute after the UpdateUI() method finishes, but now let’s assume that we replace the UpdateUI() synchronous method with an asynchronous version of it, called UpdateUIAsync():

public async void DoStuff()
{
    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        await UpdateUIAsync();
    });

    DoOtherStuff();
}

In this new version of the code, you’ll notice that the DoOtherStuff() method will eventually run before the UpdateUIAsync() has finished, which might not be what you intended to in the first place when you await’ed for the dispatcher.RunAsync() method!

This is due to the fact that the CoreDispatcher.RunAsync method has a DispatchedHandler callback which is not asynchronous:

public delegate void DispatchedHandler()

The fact that we’ve added the async/await keywords to the callback doesn’t ensure that the caller will await for it to execute!

There are a few ways suspend the background thread execution until the foreground thread signals for it to continue, and using a TaskCompletionSource is one of the easiest:

public async void DoStuff()
{
    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
    var taskCompletionSource = new TaskCompletionSource<bool>();

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        await UpdateUIAsync();

        taskCompletionSource.SetResult(true);
    });

    await taskCompletionSource.Task;

    DoOtherStuff();
}

In this version of the code, once the execution returns from await’ing the dispatcher.RunAsync() call, the background thread will carry on execution, but will then await for the taskCompletionSource.Task to finish, which will only happen after the taskCompletionSource.SetResult(true) call that we make in the main thread!

I’ve written a few CoreDispatcher extension methods to help around this issue, and added them to the next version of the Cimbalino Toolkit, but you can access them right now if you wish so! ๐Ÿ˜‰

Compiled Bindings considerations II

A few months ago I wrote my first Compiled Bindings considerations article, and seems that time has come to write some more, only this time I’m bearer of some bad news…

TL;DR

Compiled Bindings have a bug, noticeable in some scenarios, specifically when a binding has a fallback value of null (which is the default)!

Make sure to thoroughly test your app if you use compiled bindings!

So what is the big deal?

To illustrate the problem, I’ve written a small demo app!

Let’s start by checking the view models code:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class MainViewModel : ViewModelBase
{
    private CurrentTimeViewModel _currentTime;

    public CurrentTimeViewModel CurrentTime
    {
        get { return _currentTime; }
        set
        {
            _currentTime = value;
            OnPropertyChanged();
        }
    }
}

public class CurrentTimeViewModel : ViewModelBase
{
    private string _currentTimeTicks;

    public string CurrentTimeTicks
    {
        get { return _currentTimeTicks; }
        set
        {
            _currentTimeTicks = value;
            OnPropertyChanged();
        }
    }

    public CurrentTimeViewModel()
    {
        Update();
    }

    public void Update()
    {
        CurrentTimeTicks = DateTime.Now.Ticks.ToString();
    }
}

Our view model is composed of 3 classes:

  • ViewModelBase is just a standard implementation for the INotifyPropertyChanged interface, providing an OnPropertyChanged helper method to its inheritors.
  • MainViewModel will be used as the main view model for our sample and has a single property, CurrentTime.
  • CurrentTimeViewModel has a single CurrentTimeTicks property which will contain a string representing the current time in ticks; an Update helper method has also been added to this view model.

Now let’s take a look at the MainPage view:

<Page x:Class="CompiledBindings2.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="using:CompiledBindings2"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <StackPanel Margin="12">
            <TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="Current Time Ticks (Binding)" />
            <TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{Binding CurrentTime.CurrentTimeTicks}" />

            <TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="Current Time Ticks (x:Bind)" />
            <TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="{x:Bind ViewModel.CurrentTime.CurrentTimeTicks, Mode=OneWay}" />
        </StackPanel>

        <StackPanel Grid.Row="1">
            <Button HorizontalAlignment="Stretch"
                    Click="CreateChildViewModelButton_OnClick"
                    Content="Create CurrentTimeViewModel" />
            <Button HorizontalAlignment="Stretch"
                    Click="UpdateCurrentTimeViewModelButton_OnClick"
                    Content="Update CurrentTimeViewModel" />
            <Button HorizontalAlignment="Stretch"
                    Click="DestroyCurrentTimeViewModelButton_OnClick"
                    Content="Destroy CurrentTimeViewModel" />
        </StackPanel>
    </Grid>
</Page>

The MainPage view is composed of the following:

  • a TextBlock with its Text property binded to CurrentTimeViewModel.CurrentTimeTicks, using “classic” bindings
  • a TextBlock with its Text property binded to CurrentTimeViewModel.CurrentTimeTicks, using compiled bindings
  • a Button to create a new CurrentTimeViewModel instance
  • a Button to update the current CurrentTimeViewModel instance
  • a Button to destroy the current CurrentTimeViewModel instance

Finally, here’s the code behind for the MainPage view:

public sealed partial class MainPage : Page
{
    private readonly MainViewModel _viewModel;

    public MainPage()
    {
        this.InitializeComponent();

        _viewModel = new MainViewModel();

        this.DataContext = _viewModel;
    }

    public MainViewModel ViewModel
    {
        get { return _viewModel; }
    }

    private void CreateChildViewModelButton_OnClick(object sender, RoutedEventArgs e)
    {
        _viewModel.CurrentTime = new CurrentTimeViewModel();
    }

    private void UpdateCurrentTimeViewModelButton_OnClick(object sender, RoutedEventArgs e)
    {
        if (_viewModel.CurrentTime != null)
        {
            _viewModel.CurrentTime.Update();
        }
    }

    private void DestroyCurrentTimeViewModelButton_OnClick(object sender, RoutedEventArgs e)
    {
        _viewModel.CurrentTime = null;
    }
}

As you can see above, we create a new MainViewModel instance, set it as the page DataContext property, and then we have the three click event handlers, one for each of the buttons on the view.

We’ve also added a MainPage.ViewModel property to expose the current MainViewModel instance to the compiled bindings (we can’t use the DataContext property as its type is object and compiled bindings require strong-typed properties to work).

This is what you’ll get if you run the app and tap the buttons in succession:

Compiled Bindings FallbackValue bug

As you can see, the 2nd TextBlock (the one using compiled bindings) never gets the text cleared when we tap the “Destroy CurrentTimeViewModel” button!

The expected behavior is the one shown in the 1st TextBlock: if the binding value is null or unavailable, the TextBlock.Text property will set to the Binding.FallbackValue (which is null by default).

So after checking the documentation for compiled bindings, one can say without that compiled bindings are ignoring the fallback value when its value is null, and that is quite a nasty bug in the compiled bindings!

This bug has already been reported to Microsoft but as we don’t know when it will get fixed, all we can do right now is be aware of the whole issue and make sure to test our apps thoroughly to ensure we don’t end up with these problems after migrating to compiled bindings!

CultureInfo changes in UWP

Since the very first versions of the .NET Framework, developers had the System.Globalization namespace “containing classes that define culture-related information, including language, country/region, calendars in use, format patterns for dates, currency, and numbers, and sort order for strings.”

One of the most useful classes in this namespace is the CultureInfo class!

To demonstrate the usage of this class, take a look at this really simple console app code:

using System;
using System.Globalization;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("CurrentCulture: {0}", CultureInfo.CurrentCulture);
        Console.WriteLine("CurrentUICulture: {0}", CultureInfo.CurrentUICulture);
    }
}

If you run the above code with different system configurations, this is what it would output:

// Display Language = "English (US)", Location = "United States", Regional Settings = "English (US)"
CurrentCulture: en-US
CurrentUICulture: en-US

// Display Language = "English (US)", Location = "United States", Regional Settings = "Portuguese (Portugal)"
CurrentCulture: pt-PT
CurrentUICulture: en-US

// Display Language = "English (United Kingdom)", Location = "Spain", Regional Settings = "Portuguese (Angola)"
CurrentCulture: pt-AO
CurrentUICulture: en-GB

As you can see from the above results, the CurrentCulture and CurrentUICulture property values are inferred respectively from Regional Settings and Display Language; the Location however, doesn’t seem to have any effect over these two properties.

This feature allowed any app to show data using the proper currency, date, and number formats, even if the app itself wasn’t localized for those cultures!

But then came WinRT with the Windows.Globalization namespace as a replacement, and that apparently affected the way the CultureInfo class behaved…

To show the differences, I’ve created a blank Windows 8 app, and set the following code in the MainView.xaml.cs file:

using System;
using System.Globalization;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;

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

        this.Loaded += MainPage_Loaded;
    }

    private void MainPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
    {
        var messageDialog = new MessageDialog(string.Format("CurrentCulture: {0}" + Environment.NewLine + "CurrentUICulture: {1}",
            CultureInfo.CurrentUICulture,
            CultureInfo.CurrentCulture));

        messageDialog.ShowAsync();
    }
}

These are the results of running the above code:

// Display Language = "English (US)", Location = "United States", Regional Settings = "English (US)"
CurrentCulture: en-US
CurrentUICulture: en-US

// Display Language = "English (US)", Location = "United States", Regional Settings = "Portuguese (Portugal)"
CurrentCulture: en-US
CurrentUICulture: en-US

// Display Language = "English (United Kingdom)", Location = "Spain", Regional Settings = "Portuguese (Angola)"
CurrentCulture: en-GB
CurrentUICulture: en-GB

As you can see here, both the CurrentCulture and CurrentUICulture property values are now based on the selected Display Language!

In my personal opinion, this change of behavior is wrong for various reasons, but mostly because it breaks the expected known behavior of the CultureInfo class properties.

Right now you might be thinking that the impact of this change is really small, but it might actually be bigger than expect due to a specific feature: Cortana!

As of today, Cortana is still only available in a few locations, and as such, most users have “faked” their location in order to get Cortana active on their devices, but maintained the Regional Settings matching their real location!

Retrieving the “proper” CurrentCulture

One could use the Windows API GetUserDefaultLocaleName to retrieve the Regional Settings, but this only works on full Windows 10, so it’s not a “universal” way of doing it!

However, I’ve found that if you create a DateTimeFormatter instance with “US” as language, you can retrieve the culture name from the DateTimeFormatter.ResolvedLanguage property!

And here is a simple code example demonstrating how to do it:

using Windows.Globalization.DateTimeFormatting;

public class CultureInfoHelper
{
    public static CultureInfo GetCurrentCulture()
    {
        var cultureName = new DateTimeFormatter("longdate", new[] { "US" }).ResolvedLanguage;

        return new CultureInfo(cultureName);
    }
}

I honestly still don’t know how or why does this work with that Magic Stringโ„ข (others might also do the trick though), but it does, and at this stage all I care are positive results!

So there you go, this is a nice hack to retrieve a CultureInfo instance for the Regional Settings, which you can then use to parse and format values in your UWP (and WinRT) app! ๐Ÿ™‚

Compiled Bindings considerations

As you’re probably aware, Windows 10 introduced a new type of Bindings called Compiled Bindings.

And as the name might suggest, compiled bindings are a way the compiler uses to generate static code for a binding instead of using a reflection based solution, as regular bindings do.

The main advantage is quite obvious: there will be a performance gain for using static compiled code instead of using reflection!

Let’s take a look at a simple regular binding example:

<TextBlock Text="{Binding Name}" />

This binding will set the TextBlock.Text property to the value of the Name and will update it every time the Name property changes (assuming that the data context implements and raises the necessary INotifyPropertyChanged.PropertyChanged event)

To take advantage of the compiled bindings, one would rewrite it like this:

<TextBlock Text="{x:Bind Name, Mode=OneWay}" />

Notice that I added the Mode=OneWay on the expression above?

Well, that is actually required due to a fundamental difference between regular bindings and compiled bindings: while the regular bindings default mode is OneWay, compiled bindings default mode is OneTime!

This is a really important piece of information that I’ve seen a lot of developers not taking notice, so make sure to fix those binding expressions correctly when you migrate to compiled bindings!