#UWPXAML – Compiled Binding – What’s new in the Anniversary Update?

Coming this summer, Windows 10 Anniversary Update will be more or less a Windows 10 v2.0.
With it comes a lot of new things for the windows app development, and a lot of new features and fixes for Compiled Binding.

Today we’ll see what those new features are and how to use them.

If you want to try them out yourself, you’ll need a Windows Insider build of Windows 10 with its Windows SDK and create a UWP project targeting a min version at least equals to Build 14383. Do not install it on your main work station, it will break any non-Anniversary Update apps.

For this post, I’ll use Windows 10 Build 14383 (available on Fast Ring) with Visual Studio 2015 Update 3.
The Windows SDK for Build 14383 can be found here: https://insider.windows.com/

In case you missed it, I wrote a few posts about compiled binding in the past.
Feel free to read them (again).

 

Function binding

Previously, it was possible to directly bind events to methods which followed specific rules regarding their parameters, but we were unable to bind the result of a method to a property without a converter which was calling the method for us.

Now, it’s possible to bind methods directly to properties without the need for a converter!
You can provide whatever method you like as long as it has a public accessor and you provide the parameters.

MainPage.xaml.cs

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

    public string GetHelloWorld()
    {
        return "Hello World";
    }

    public Person Roberts = new Person()
    {
        Firstname = "Dread Pirate",
        Lastname = "Roberts"
    };
}

Person.cs

public class Person
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }

    public string GetFullname()
    {
        return $"{Firstname} {Lastname}";
    }
}

MainPage.xaml

<TextBlock Text="{x:Bind GetHelloWorld()}" />
<TextBlock Text="{x:Bind Roberts.GetFullname()}" />

The method can have parameters.
You can provide them by setting constants in the XAML or by using data from your ViewModel.

MainPage.xaml.cs

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

    public DateTime Today = DateTime.Now;

    public Person Someone = new Person()
    {
        Firstname = "Some",
        Lastname = "One"
    };        

    public string GetPersonFullname(Person person)
    {
        return person.GetFullname();
    }
}

MainPage.xaml

<TextBlock Text="{x:Bind Today.ToString('d', {x:Null})}" />
<TextBlock Text="{x:Bind GetPersonFullname(Someone)}" />

Does the binding is automatically updated when the data is updated?
Well, it is said to work if you set the Mode of the compiled binding to OneWay/TwoWay but I wasn’t able to compile it under VS2015. A few not really understandable compile errors appeared when I used TwoWay binding.

Along that, you may notice some errors appearing in the Error list when using parameters inside your binded functions stating « A value does not fall within the expected range ». It’s a bug of VS2015, but it compiles and runs fine anyway.

I hope those annoying errors will be fixed in the release version.
 

Dictionary indexers

As part of supporting most use cases without the need for a converter, x:Bind now supports access to a specific key in a dictionary.

MainPage.xaml.cs

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

    public Dictionary<string, string> Dictionary = new Dictionary<string, string>()
    {
        { "A", "Alpha" },
        { "B", "Beta" },
        { "C", "Charlie" },
    };
}

MainPage.xaml

<TextBlock Text="{x:Bind Dictionary['A']}" />
<TextBlock Text="{x:Bind Dictionary['B']}" />
<TextBlock Text="{x:Bind Dictionary['C']}" />

It works great but there is a big shortcoming: You can only use constant strings directly set in the XAML.
Using anything else than a string, like an integer, will result in a compile error.
Even string data from your ViewModel won’t work.
 

Explicit value cast

Contrary to classic Databinding which uses duck typing to check if the binding is valid, compiled binding checks at compile time that the given data matches the property to which it is binded to.
In other words, if the value you’re trying to bind has no implicit cast to the type of the property, you can’t bind it using x:Bind without a converter.
Even if the value’s type declares an explicit cast…

As of the Anniversary Update, you will be able to declare an explicit cast inside a compiled binding, C#-style.

MainPage.xaml.cs

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

    public bool? IsThreeStateNull = null;
}

MainPage.xaml

<CheckBox Content="IsThreeState = False" IsThreeState="{x:Bind (x:Boolean)IsThreeStateNull}" />

When casting explicitly, you’ll need to refer to the class type by its XAML namespace.
In this case, Boolean is part of the « x: » namespace declaration.
 

Implicit Visibility conversion

Who don’t know the legendary BooleanToVisibilityConverter?
Everyone, since the first time WPF came around, implemented it over and over in every projects.

x:Bind no longer requires that, it now converts booleans to Visibility by itself! Hurray!
You just need to bind a boolean to a property like Visibility.

MainPage.xaml.cs

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

    public bool IsVisibleFalse = false;
    public bool IsVisibleTrue = true;
}

MainPage.xaml

<TextBlock Text="I'm not visible!" Visibility="{x:Bind IsVisibleFalse}" />
<TextBlock Text="I'm visible!" Visibility="{x:Bind IsVisibleTrue}" />

 

Conclusion

You can find a sample project on GitHub regrouping all the examples we saw in this post: http://github.com/TimLariviere/CompiledBinding-AnniversarySample

Écriture/lecture/modification de fichiers dans un projet Universel app/UWP et cordova

Dans nos applications, nous avons pris le parti d’écrire nos fichiers en JSON. Nous avons donc conçu une abstraction (en WinJS, avec un système de promises) qui nous permet d’utiliser des méthodes claires et simples sur toutes les plateformes (WinRT/UWP ou Cordova (iOS/Android) )

Ce module « DataContainer » est disponible dans notre libraire WinJSContrib (Github)

Dans WinJSContrib.DataContainer, nous avons 4 fichiers qui exposent les mêmes méthodes avec des implémentations différentes :

  • read : lecture d’un élément
  • save : enregistrement d’un élément
  • remove : suppression d’un élément
  • list : liste des fichiers d’un container
  • child : création/accès container enfant

Dans une application WinRT/UWP nous allons naturellement utiliser la couche WinRT/UWP pour écrire/lire les fichiers. Pour cela il suffit d’inclure le fichier « winjscontrib.datacontainer.winrt.file.js »

Dans une application cordova IOS ou Android, nous avons plusieurs choix :

  • Utiliser une base de données : winjscontrib.datacontainer.cordova.database.js
  • Utiliser le système de fichiers avec le plugin file : « winjscontrib.datacontainer.cordova.file.js »
  • Utiliser le localStorage : « winjscontrib.datacontainer.localstorage.js » (utilisable en WinRT aussi)

Ensuite, il faut instancier un container parent et l’utiliser partout dans l’application.

Dans le JS des applications Windows 8/Phone il suffit d’instancier le container (dossier) parent :

MyApp.Data.container = new WinJSContrib.DataContainer.WinRTFilesContainer(undefined, { logger: WinJSContrib.Logger });

Et changer WinRTFilesContainer par notre choix (CordovaDatabaseContainer par exemple) pour l’application cordova en faisant attention de ne l’appeler qu’après l’enclenchement de l’évènement deviceready.

Et c’est tout, la magie s’opère à l’intérieur de notre librairie 🙂

Quelques exemples d’utilisation :

  • Pour lire un fichier :
  • Data.container.read(&quot;objKey&quot;).then(function (data) { }, function (error) { });
    
  • Supprimer un fichier :
  • Data.container.remove(&quot;objKey&quot;).then(function () { }, function (error) { });
    
  • Enregistrer un fichier :
  • Data.container.save(&quot;objKey&quot;,obj).then(function () { }, function (error) { });
    
  • Accès à un container enfant (sous dossier) avec la lecture d’un fichier fichier :
  • Data.container.child(folderid).read(&quot;subObjKey&quot;).then( function (subObjInFolderID) { }, function (error) { }));
    
  • Liste des fichiers dans un container :
  • Data.container.list().then(function (res) {}, function (error) { });
    

Workaround to use and debug TypeScript with UWP apps and Visual Studio 2015 update 2/3

Since the Update 2 of Visual Studio, the TypeScript debugging in UWP apps is broken.

After a lot of discussions on the TypeScript repo, Mine Yalcinalp Starks give me a workearound that works just perfectly 🙂

And here the solution (I assume you’re running in an English locale here, otherwise I don’t think the workaround is applicable):

Close VS.
In an administrator command prompt:

cd %ProgramFiles(x86)%\msbuild\microsoft\visualstudio\v14.0\typescript
mkdir en
copy *.xaml en
copy TypeScript.Tasks.dll en\TypeScript.Tasks.resources.dll

The behavior that breaks the TypeScript integration in UWP (In reality, typescript is not officially supported in UWP apps, it will be in VS15 « next ») is potentially due to a TypeScript installation bug.

Tricks : Gérer son numéro de version au niveau de la solution

Si comme moi, vous avez toujours rêvé de pouvoir gérer son numéro de version au niveau de solution et non au niveau de chaque projet cet article est fait pour vous !

Marche à suivre

  1. Click droit sur la solution -> Ajouter un nouvel item -> Classe Visual C#
  2. Nommez le fichier « SharedAssembyInfo.cs »
  3. Reprenez toutes les infos d’un « AssemblyInfo.cs » d’un projet existant et copier-coller le contenu dans « SharedAssembyInfo.cs ». Les fichiers « AssemblyInfos.cs » se trouvent dans la rubrique « Properties » située juste au-dessus de « Références ».
  4. Mettez en commentaire tout le contenu des différents « AssemblyInfo.cs »
  5. Sur chaque projet :
    1. Click droit -> Ajouter élément existant
    2. Sélectionner le « SharedAssembyInfo.cs »
    3. Choisir d’ajouter en tant que lien
    4. Faites glisser le fichier ajouté au projet dans le dossier « Properties »

A savoir

Vous n’êtes pas obligé de partager toutes les informations dans le « SharedAssembyInfo.cs », tout ce qui est spécifique à chaque projet vous pouvez le laisser dans le « AssemblyInfos.cs » du projet.

Pour allez plus loin

Savez-vous que vous pouvez générer un numéro de build sans usine de build depuis Visual Studio? Pour cela il suffit de :

  1. Mettre en commentaire l’attribut « [assembly: AssemblyFileVersion(« 1.0.0.0 »)]» que l’on trouve dans « SharedAssembyInfo.cs » ou « AssemblyInfos.cs ». Seul l’attribut « AssemblyVersion » doit être spécifié.
  2. Mettre l’attribut « AssemblyVersion » sous la forme : « [assembly: AssemblyVersion(« Majeur.Mineur.* »)] »

Après ça, à chaque build, Visual Studio va remplacer l’étoile par un « numéro de build » et un « numéro de révision » :

  • Numéro de build : Le nombre de jour depuis le 1er Janvier 2000.
  • Numéro de révision : Le nombre de secondes depuis minuit divisé par 2.

 

J’espère que cet article vous aura été utile 😉

 

Sources

http://weblogs.asp.net/ashishnjain/sharing-assembly-version-across-projects-in-a-solution

http://www.csharpcity.com/2012/visual-studio-automatic-version-numbering/

https://msdn.microsoft.com/en-us/library/k49w9389(v=vs.110).aspx