Le Post de MCNEXT

Les articles des consultants de MCNEXT

Le Windows Store for Business de Microsoft est enfin là !

Après plusieurs mois d’attente le « Business Store » est enfin disponible et accessible gratuitement avec quelques prérequis :

  • Avoir un Azure Active Directory.
  • Des postes clients sous Windows 10 uniquement (Desktop/Phone)
  • (Énormément de patience pour le déploiement…)

(Pour les clients sous Windows 8 et Windows 8.1, ou ceux qui n’ont pas d’Azure AD, nous avons une solution pour vous !)

Comment s’inscrire ?

La première étape se déroule sur https://businessstore.microsoft.com, l’administrateur général de l’AD se connecte avec le compte de l’organisation.

La création du store est immédiate, mais son déploiement prend du temps.

L’administrateur peut attribuer les droits à d’autres utilisateurs de l’AD de gérer le store (directement dans le BO du store) pour les actes d’achats, d’attributions de licences et de publications.

login.png

Les applications grand public :

Après « l’achat » (visiblement pour l’instant nous ne pouvons acheter que des applications gratuites), l’attribution de la licence peut être globale (au niveau de l’organisation), par groupe ou par utilisateur. Le déploiement prend plusieurs heures (+12h)

achat.png

 Les application LOB :

Le processus est long puisqu’il se passe en plusieurs actes :

  • Premier acte :
    • L’administrateur invite un éditeur LOB avec une adresse mail pour que celui-ci puisse attribuer à l’organisation une ou des applications. (Éditeur LOB = un simple compte de développement qui possède un accès au Windows Dev Center https://dev.windows.com)

lob.png

  • Deuxième acte :
    • L’éditeur publie ou met à jour une application en précisant dans la section « tarifs et disponibilités », le store d’entreprise qu’il souhaite viser (une même app LOB peut être diffusée sur différents Business Stores).
  • Troisième acte :
    • Après la validation de l’application par Microsoft (cette étape dure entre quelques heures à quelques jours), l’application est disponible coté BO du Business Store, et c’est à ce moment là que l’administrateur peut l’ajouter au catalogue, de la même manière qu’une application grand public (avec les droits qui vont avec et l’attente du déploiement qui prend aussi plusieurs heures)

Configuration du poste client (Desktop/Phone):

L’étape la plus simple se passe coté poste client où il suffit de se connecter ou d’ajouter (si ce n’est pas déjà le cas) le compte utilisateur rattaché à l’AD directement dans l’application du store. Un nouvel onglet va apparaitre avec la liste des applications attribuées que l’utilisateur pourra alors installer.

Sans titre.png

A vos déploiements !

#UWPXAML – Compiled Binding – Incremental rendering with x:Phase

Coming with Windows 10 are a lot of new features especially for XAML when creating a Universal Windows Platform application aka. UWP app. We can mention a few of them: new controls (as the RelativePanel, the SplitView and more); new tools for building responsive and adaptive UI (AdaptiveTrigger, Extension SDKs, etc.); and a new way to bind data to the UI, Compiled Binding.

This series on Compiled Binding will be composed of several parts:

 

Dealing with long list of data

You often have to work on apps that have a great deal of data. Those data are best displayed on list when they’re of same type, and you generally want to let your users scroll through it without noticeable performance issues.

To enable this, virtualized lists have been created.

Only a handful of items, that are visible to the user, are rendered at the same time while other items are simply not rendered at all. When the user scrolls through the list, rendered items are recycled to match where the user is in the list, thus keeping your memory usage low while still giving to your user what he needs.

This gives your users the illusion that your app is fast.

But sometimes, your items’ DataTemplate can be complex and when the user scrolls through the list, the CPU might not keep up and fully render new items in time. In that case, the list will display placeholder items until rendered items are ready. A quirky user experience may result from that.

To help you have more control on how to optimize the rendering of your items in those circumstances, Windows 8.1 added the event ContainerContentChanging allowing you to progressively render your items in a ListViewBase-derived control.
 

ContainerContentChanging event

The idea behind ContainerContentChanging is quite simple. By handling that event, you can progressively render the items that are visible to the user. This is done by using phases.

Let’s say that you have a list of books, each with a title, a subtitle and a description.
The most important information of your books is the Title property, so it must be displayed whenever possible. The Subtitle property is important but not crucial for the user experience while the Description property is not important.

With the ContainerContentChanging event, you can delay the rendering of the Subtitle and Description properties to later, when the CPU will be more available. The event is called multiple times if necessary, for each pair of container / data that need to be rendered.

Each time the event is raised for the same container / data pair is called a phase. The phase number is provided through the ContainerContentChangingArgs parameter, Phase property.

You can then check the phase number to decide which information should be loaded according to your importance scale.

There we can decide to let the Title property on Phase 0, the Subtitle property on Phase 1 and the Description property on Phase 2.

Phase 0 will be part of the first rendering of the item, while Phase 1 will be done once all current items’ Phase 0 have been rendered, and so on until all phases of all items are done.

Here’s an example that can be found on MSDN:
ListView and GridView UI optimization

XAML

<Page
    x:Class="LotsOfItems.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:lotsOfItems="using:LotsOfItems"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{x:Bind ViewModel.ExampleItems}" ContainerContentChanging="GridView_ContainerContentChanging">
            <GridView.ItemTemplate>
                <DataTemplate x:DataType="lotsOfItems:ExampleItem">
                    <StackPanel Height="100" Width="100" Background="OrangeRed">
                        <TextBlock Text="{x:Bind Title}"/>
                        <TextBlock Opacity="0"/>
                        <TextBlock Opacity="0"/>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Page>

C#

namespace LotsOfItems
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.ViewModel = new ExampleItemViewModel();
        }

        public ExampleItemViewModel ViewModel { get; set; }

        // Display each item incrementally to improve performance.
        private void GridView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
        {
            if (args.Phase != 0)
            {
                throw new System.Exception("We should be in phase 0, but we are not.");
            }

            // It's phase 0, so this item's title will already be bound and displayed.

            args.RegisterUpdateCallback(this.ShowSubtitle);

            args.Handled = true;
        }

        private void ShowSubtitle(ListViewBase sender, ContainerContentChangingEventArgs args)
        {
            if (args.Phase != 1)
            {
                throw new System.Exception("We should be in phase 1, but we are not.");
            }

            // It's phase 1, so show this item's subtitle.
            var templateRoot = args.ItemContainer.ContentTemplateRoot as StackPanel;
            var textBlock = templateRoot.Children[1] as TextBlock;
            textBlock.Text = (args.Item as ExampleItem).Subtitle;
            textBlock.Opacity = 1;

            args.RegisterUpdateCallback(this.ShowDescription);
        }

        private void ShowDescription(ListViewBase sender, ContainerContentChangingEventArgs args)
        {
            if (args.Phase != 2)
            {
                throw new System.Exception("We should be in phase 2, but we are not.");
            }

            // It's phase 2, so show this item's description.
            var templateRoot = args.ItemContainer.ContentTemplateRoot as StackPanel;
            var textBlock = templateRoot.Children[2] as TextBlock;
            textBlock.Text = (args.Item as ExampleItem).Description;
            textBlock.Opacity = 1;
        }
    }
}

As you can see, our DataTemplate contains three TextBlocks: one for the Title property, one for the Subtitle property and one for the Description property.

Title being the most important, the control is already databound in the DataTemplate while the others are simply not set and are even hidden from users with Opacity at 0.

Then we add an event handler to the ContainerContentChanging event of the GridView.

When the event is raised in GridView_ContainerContentChanging method, it is Phase 0, the book’s title is rendered.

x:Phase
 

To notify that we expect another phase to occur, we register an update callback through the ContainerContentChangingArgs.RegisterUpdateCallback method. In that callback, that will be called once all items’ Phase 0 are done, we retrieve the second TextBlock control to load its content, the book’s Subtitle, and display it by setting the Opacity to 1.

x:Phase
 

Once it’s done, we register for a third phase to display the book’s description.

x:Phase
 

If the user has scrolled past too many items and the list control wants to recycle containers before we have rendered all the phases, ContainerContentChanging is no longer called for these container / data pairs and the containers are recycled for other data, thus ending the rendering of those previous items.

While ContainerContentChanging is simple to use, its implementation can be quite tedious. Even more when you need to change the DataTemplate over the course of development, you found yourself re-implementing it over and over.

There comes to the rescue {x:Bind} and its x:Phase attribute.
 

Simplifying ContainerContentChanging with x:Phase

Based on the ContainerContentChanging event, x:Bind introduces a shortcut notation to use those rendering phases: x:Phase.

It uses the exact same principle that we’ve seen on the last example, except you don’t have to implement ContainerContentChanging. It’s done for you by code-generation when using {x:Bind}.

To use it, it’s really simple. Just set the x:Phase attribute on an {x:Bind} databound control.

XAML

<GridView ItemsSource="{x:Bind ViewModel.ExampleItems}">
    <GridView.ItemTemplate>
        <DataTemplate x:DataType="lotsOfItems:ExampleItem">
            <StackPanel Height="100" Width="100" Background="OrangeRed">
                <TextBlock Text="{x:Bind Title}"/>
                <TextBlock Text="{x:Bind Subtitle}" x:Phase="1"/>
                <TextBlock Text="{x:Bind Description}" x:Phase="2"/>
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

As we’ve seen with ContainerContentChanging, the higher the phase number, the later the control will be rendered. If no phase is set, it’ll be 0 by default.

Note: Those phases don’t have to be contiguous with x:Phase.

In this case, the CPU will try to render the book’s title, then the book’s subtitle and finally the book’s description instead of trying to render them all at once and failing to keep up with the scroll applied by the user.

When the control’s phase is not yet reached, they are set to Opacity=0 thus hiding them. When their phase is reached, the compiled binding is resolved and the controls are displayed.

The result is the same but it is less tedious to implement. You just have to set an attribute on the databound control as opposed to doing a whole implementation of the ContainerContentChanging event.

Later, if you need to change the DataTemplate, it will be way easier.

Just one thing, x:Phase needs x:Bind in order to work. If not present, x:Phase will simply be ignored. So if you need to delay the rendering of a not-databound control, you still have to use the ContainerContentChanging event, that also applies if you need more than just hiding a control for a time.
 

Going further

MSDN
« x:Phase attribute »
https://msdn.microsoft.com/en-us/library/windows/apps/mt204790.aspx

MSDN
« ListView and GridView UI optimization »
https://msdn.microsoft.com/en-us/library/windows/apps/mt204776.aspx

Channel 9
« Improving XAML performance »
https://channel9.msdn.com/Events/Windows/Developers-Guide-to-Windows-10-RTM/Improving-XAML-Performance

Build 2015
« Data Binding: Boost Your Apps’ Performance Through New Enhancements to XAML Data Binding » https://channel9.msdn.com/Events/Build/2015/3-635

#UWPXAML – Compiled Binding – Binding to events

Coming with Windows 10 are a lot of new features especially for XAML when creating a Universal Windows Platform application aka. UWP app. We can mention a few of them: new controls (as the RelativePanel, the SplitView and more); new tools for building responsive and adaptive UI (AdaptiveTrigger, Extension SDKs, etc.); and a new way to bind data to the UI, Compiled Binding.

This series on Compiled Binding will be composed of several parts:

 

{x:Bind} and events

As we’ve seen in the previous part « Part 1: Binding to data« , x:Bind is great when you want to bind various source of data to your UI. It does mostly the same things as classic binding but with better performance and compile-time checks.

x:Bind doesn’t stop here. It goes a step further than its cousin: it can also bind event handlers to events, regardless if it has been thought by the control’s author unlike {Binding}, which needs ICommand support to be built into the control.

All that in a natural way thanks to code generation introduced by compiled binding.
 

Before {x:Bind}

Before compiled binding, you had three ways to handle events in XAML.

1st Way: Register an event handler defined in your code behind directly to your control’s event in XAML. That’s the most common way of doing it as it’s how the XAML framework has been built.

<Button Click="CodeBehind_ButtonClicked" />

 

2nd Way: Use Command properties when available in conjunction with ICommand. This allows you to define your event handler outside the code-behind class, like in your ViewModel.

public class ViewModel
{
    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get { return (_clickCommand ?? _clickCommand = new RelayCommand<object>(this.OnButtonClicked)); }
    }

    private void OnButtonClicked(object parameter) { ... }
}

Then in your XAML file, you just have to bind to it.

<Button Command="{Binding ClickCommand}" CommandParameter="HelloWorld" />

One limitation: the control must have built-in support for it. And well, apart from Button and its Command property, barely any other control have such thing.

For example, if you want to handle SelectionChanged of ListView, there isn’t any property allowing you to react to SelectionChanged event from your ViewModel without using the first way we saw.
 

3rd Way: Use Behavior to bind ICommand to any event.

<ListView>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <command:EventToCommand Command="{Binding SelectionChangedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListView>

To get around the previous limitation, Blend added an Interactions SDK that allows you, among other things, to create custom behaviors. These behaviors can be attached to controls, that way you can extend on the control’s behavior without having to create another control that inherits from the former.

You can create a behavior that subscribes to whatever event you need and let it call your ICommand, just like the Command property of Button does.

Behaviors with this purpose already exist in MVVM libraries such as EventToCommand from the well-known MVVMLight.
 

{x:Bind}, the Event Handler

Now in UWP apps, you have another way to do so: {x:Bind}.

Let’s say you have a ViewModel and you want to handle the SelectionChanged event of a ListView in a method named OnSelectionChanged, that is in your ViewModel.

public class MyPageViewModel
{
    public ObservableCollection<Book> Books { get; set; }

    public void OnSelectionChanged(object sender, SelectionChangedEventArgs args) { ... }
}

With {x:Bind}, all you have to do is just bind OnSelectionChanged of your ViewModel to the event you want to handle.

<ListView ItemsSource="{x:Bind ViewModel.Books}" SelectionChanged="{x:Bind ViewModel.OnSelectionChanged}" />

There, you just bound yourself an event! It’s that easy.

As you can see, to hook up an event to a method, you just need to use the same markup extension like you would with data binding. Behind, the compiler will add the required logic to call your method when the event is raised.

But when doing so, the compiler expects that the method you try to bind is public and respects one of these conditions:

  • Have the exact event signature
  • Have the same event signature, but parameters can be of a more generic type (up to object)
  • Have no parameter at all

Let’s take a look at how to meet these conditions when binding to the Click event of a button.

XAML

<Button Click="{x:Bind OnButtonClicked}" />

C#

// Exact event signature
public void OnButtonClicked(object sender, RoutedEventArgs args) { … }

// Same event signature, args' type is more generic (RoutedEventArgs --> EventArgs)
public void OnButtonClicked(object sender, EventArgs args) { … }

// Same event signature, args' type is now object
public void OnButtonClicked(object sender, object args) { … }

// No parameter
public void OnButtonClicked() { … }

Asynchronous methods are also supported, just set the « async » keyword on your method signature.

// Asynchronous event handler
public async void OnButtonClicked() { … }

Where can I put those methods, you may ask.

Well, you can put them in your code-behind class (this is x:Bind’s root context, remember?) or you can put them in your ViewModel! No need for ICommand nor EventToCommand behavior now. It just got a whole lot easier compared to what we were used to with classic binding, while using MVVM.

<!-- OnButtonClicked declared in code-behind (except when used in DataTemplate) -->
<Button Click="{x:Bind OnButtonClicked}" />

<!-- OnButtonClicked declared in the ViewModel -->
<Button Click="{x:Bind ViewModel.OnButtonClicked}" />

<!-- OnButtonClicked declared on a data model exposed by the ViewModel -->
<Button Click="{x:Bind ViewModel.LastReadBook.OnButtonClicked}" />

 

Moving on to the last part

We’ve seen pretty much everything x:Bind can offer, or have we?
There is one last neat feature that x:Bind brings: Incremental rendering in list controls.
To learn more about this, head to « Part 3: Incremental rendering with x:Phase« .

#UWPXAML – Compiled Binding – Binding to data

Coming with Windows 10 are a lot of new features especially for XAML when creating a Universal Windows Platform application aka. UWP app. We can mention a few of them: new controls (as the RelativePanel, the SplitView and more); new tools for building responsive and adaptive UI (AdaptiveTrigger, Extension SDKs, etc.); and a new way to bind data to the UI, Compiled Binding.

This series on Compiled Binding will be composed of several parts:

 

Databinding with {x:Bind}

Now that you know what compiled binding is and in what it differs from classic binding, let’s see how to use it in different conditions. If you don’t, see « Part 0: Compiled Binding, what is it? »
 

{x:Bind} over a simple value

To start this series of compiled binding examples, we will see how to bind to a single scalar property.

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public string ApplicationTitle = "UWP Series - Compiled Binding";

    public MainPage()
    {
        this.InitializeComponent();
    }
}

Remember that I said x:Bind’s root context is the instance of control which we are currently declaring in its XAML file?

To bind to a value, we need to define it in the « .xaml.cs » file of the control with the public accessor as x:Bind doesn’t have access to protected/private fields. We don’t set the DataContext property because it’s not the root context of compiled binding.

This is also useful to avoid DataContext with compiled binding as it is of type Object and if you need to access some sub-properties of the type you put in DataContext, x:Bind will require that you define the real type in your path like this « {x:Bind Path=DataContext.(local:User.FirstName)}« , reducing the readability of your XAML.

So here, we define the ApplicationTitle string as a public field, but we can also declare it as a property.

Now that we have access to it with x:Bind in XAML, let’s see how to bind to it.

MainPage.xaml

<Page x:Class="UWPSeries.CompiledBinding.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Margin="8" Text="{x:Bind ApplicationTitle}" />
    </Grid>

</Page>

As you can see, it is the same as classic binding, we just have replaced the keyword Binding (also known as Markup Extension) by x:Bind and it works!

Compiled Binding
 

{x:Bind} versus the world

From now on, every code samples will use this Book class.

Book.cs

public class Book
{
    public string ImageUrl { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
}

 

{x:Bind} over a ViewModel

Using x:Bind with a ViewModel is the same as a scalar data, you can define your ViewModel as a public field/property in your « .xaml.cs » file, and then x:Bind will have access to it in the XAML file.

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public Book LastReadBook = new Book
    {
        ImageUrl = "ms-appx:///Images/H2G2_UK_front_cover.jpg",
        Title = "The Hitchhiker's Guide to the Galaxy",
        Author = "Douglas Adams"
    };

    public MainPage()
    {
        this.InitializeComponent();
    }
}

MainPage.xaml

<Image Source="{x:Bind LastReadBook.ImageUrl}" />
<TextBlock Grid.Column="1" VerticalAlignment="Center">
    <Run Text="{x:Bind LastReadBook.Title}" />
    <LineBreak />
    <Run Text="{x:Bind LastReadBook.Author}" />
</TextBlock>

As you can see, we specify in the binding path the name of the public field we declared in the « .xaml.cs » file followed by a point to access its properties.

Compiled Binding
 

{x:Bind} in a DataTemplate

To use x:Bind in a DataTemplate, there is only one mandatory step. You need to declare to the DataTemplate what will be the type of the context to render. This is done by setting the attribute « x:DataType » on the DataTemplate to the name of the type you will use.

<DataTemplate x:DataType="local:Book">
    <Grid Height="150">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Image Source="{x:Bind ImageUrl}" />
        <TextBlock Grid.Column="1" VerticalAlignment="Center">
            <Run Text="{x:Bind Title}" />
            <LineBreak />
            <Run Text="{x:Bind Author}" />
        </TextBlock>
    </Grid>
</DataTemplate>

One thing: in DataTemplate, the root context of compiled binding is the current item you are trying to render just like with classic binding. So here, when using « {x:Bind Title} », you bind to the current item’s title.

Compiled Binding
 

Special case : {x:Bind} in a ResourceDictionary

When you are creating a DataTemplate, you may want to put it in a separate ResourceDictionary to allow the reuse of this DataTemplate.

But when doing so with compiled binding, you get a build error stating « This Xaml file must have a code-behind class to use {x:Bind}. »

As I said in the previous part, compiled binding is achieved by doing code generation in the « .xaml.g.cs » file linked to your « .xaml » file where you are using x:Bind. But when putting a DataTemplate with compiled binding in a ResourceDictionary, as the dictionary doesn’t have a « .xaml.cs » file, also called a code-behind class, the compiler can’t associate the file generated to your resource dictionary.

To resolve this, you need to create that missing file, to create a partial class that inherits from ResourceDictionary and declare this class with « x:Class » in your ResourceDictionary’s XAML.

DataTemplateResourceDictionary.xaml.cs

public partial class DataTemplateResourceDictionary : ResourceDictionary
{
    public DataTemplateResourceDictionary()
    {
        this.InitializeComponent();
    }
}

DataTemplateResourceDictionary.xaml

<ResourceDictionary
    x:Class="UWPSeries.CompiledBinding.DataTemplateResourceDictionary"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWPSeries.CompiledBinding">

    <DataTemplate x:DataType="local:Book" x:Key="BookDataTemplate">
        <Grid Height="150">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Image Source="{x:Bind ImageUrl}" />
            <TextBlock Grid.Column="1" VerticalAlignment="Center">
                <Run Text="{x:Bind Title}" />
                <LineBreak />
                <Run Text="{x:Bind Author}" />
            </TextBlock>
        </Grid>
    </DataTemplate>

</ResourceDictionary>

Tip: To simplify this step, you can use the file template « Blank Page » of Visual Studio like you would to create a new page, but once the appropriate files created (« .xaml » and « .xaml.cs »), you change the Page tags to ResourceDictionary tags. All will be set up correctly allowing you to use x:Bind.

Last step is to reference your ResourceDictionary to be used by your application.

As we have created a class to hold the generated binding logic, we can’t use the classic way of declaring ResourceDictionary:

App.xaml

<Application x:Class="UWPSeries.CompiledBinding.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:UWPSeries.CompiledBinding"
             RequestedTheme="Light">

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="DataTemplateResourceDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>

Instead, we declare it by instantiating it directly.

App.xaml

<Application
    x:Class="UWPSeries.CompiledBinding.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWPSeries.CompiledBinding"
    RequestedTheme="Light">

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <local:DataTemplateResourceDictionary />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>

 

{x:Bind} over another control

x:Bind also has the capability to bind to another control inside the page/usercontrol you are working on, like ElementName and RelativeSource from classic binding.

This is easily done because as we saw in « {x:Bind} over a simple value« , {x:Bind} has access to the page instance. Setting a name to a control make it available in the page’s code-behind in a field of the same name. x:Bind can then use this named control in its path to bind to a property of it.

MainPage.xaml

<TextBox x:Name="InputTextBox" Text="I'm binded" />
<TextBlock Margin="8" Text="{x:Bind InputTextBox.Text, Mode=OneWay}" />

I set the binding as OneWay because x:Bind is by default OneTime and thus not updating when the user starts typing in the textbox.

Compiled Binding
 

Going further

MSDN
« Data binding in depth »
https://msdn.microsoft.com/en-us/library/windows/apps/mt210946.aspx

Channel 9
« Improvements to XAML data binding »
https://channel9.msdn.com/Events/Windows/Developers-Guide-to-Windows-10-RTM/Improvements-to-XAML-data-binding

Build 2015
« Data Binding: Boost Your Apps’ Performance Through New Enhancements to XAML Data Binding » https://channel9.msdn.com/Events/Build/2015/3-635
 

Next time on Compiled Binding: binding to events

Data binding with x:Bind is great like we’ve just seen, but what about event binding?
Head to « Part 2: Binding to events » to learn about how to use compiled binding with events.

#UWPXAML – Compiled Binding – What is it?

Coming with Windows 10 are a lot of new features especially for XAML when creating a Universal Windows Platform application aka. UWP app. We can mention a few of them: new controls (as the RelativePanel, the SplitView and more); new tools for building responsive and adaptive UI (AdaptiveTrigger, Extension SDKs, etc.); and a new way to bind data to the UI, Compiled Binding.

This series on Compiled Binding will be composed of several parts:

 

A quick refresh on Classic Binding

Before going into details about Compiled Binding, let’s get a refresh on “classic” binding.

If you ever have developed a XAML app (with WPF, Silverlight, Windows Phone or Windows 8 Store App), you’ll be most likely familiar with classic data binding.

It uses the {Binding} syntax to pass, observe and update an underlying data to the view easily, therefore simplifying separation of concerns: the view doesn’t have to know about the data, retrieve and update logic being handled by a binding source object created by {Binding} thus making it best used with the MVVM pattern.

Here’s a code sample using classic binding:

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new Person() { LastName = "Doe", FirstName = "John" };
    }
}

MainPage.xaml

<StackPanel>
    <TextBlock Text="{Binding LastName}" />
    <TextBlock Text="{Binding FirstName}" />
</StackPanel>

FirstName and LastName here are called paths, they will be resolved at runtime, requiring a small overhead due to the use of reflection.
 

Introducing Compiled Binding

What is Compiled Binding?

Introduced with Windows 10, Compiled Binding is very similar to Classic Binding as it serves the same purpose but with some slight differences.

Compiled Binding is used with the {x:Bind} syntax as opposed to the {Binding} syntax of Classic Binding. It still uses the notifying interfaces (like INotifyPropertyChanged) to watch for changes but {x:Bind} is by default OneTime compared to {Binding} which is OneWay.

The reason for that is that most of the time, you just want to display a value on screen and don’t need it to change over the lifetime of your page. Setting binding to be OneTime by default, remove the need to watch for changes and thus reduce CPU and memory usage.

You can still use OneWay and TwoWay binding, you just need to set it like you normally would with classic binding:

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public Person Person = new Person() { LastName = "Doe", FirstName = "John" };

    public MainPage()
    {
        this.InitializeComponent();
    }
}

MainPage.xaml

<TextBlock Text="{x:Bind Person.LastName, Mode=OneWay}" />
<TextBox Text="{x:Bind Person.FirstName, Mode=TwoWay}" />

The main difference, as the name implies, is that the binding is actually « compiled », the paths are resolved at compile-time rather than runtime like classic binding, this permits to have a better troubleshooting experience (mistyped or invalid paths are treated as build error instead of just outputting an error message in the console) and remove the overhead due to reflection usage, which are both great.

This compilation is achieved by code generation. When you use {x:Bind} instead of {Binding}, the compiler will add logic into the « .xaml.g.cs » file corresponding to your « .xaml » file.

Data binding with {x:Bind} has another feature that {Binding} doesn’t have: incremental rendering of the items in ListViewBase-derived controls like ListView and GridView. This is done by using both {x:Bind} and the attribute x:Phase on controls inside your DataTemplate.

<DataTemplate x:Bind="local:Person">
    <StackPanel>
        <TextBlock Text="{x:Bind LastName}" />
        <TextBlock Text="{x:Bind FirstName}" x:Phase="1" />
    </StackPanel>
</DataTemplate>

Based on the ContainerContentChanging event that came with Windows 8.1, x:Phase allows you to progressively render your DataTemplate inside long list of data while the user is scrolling fast.

As you can see in the example, just set the x:Phase attribute on an x:Bind databound element and its rendering will be delayed until the CPU will have more time for it. If no phase is set, it’s by default phase 0, so whenever the item can be rendered, the element will also be.

That way, you have control on what to display first instead of just showing a placeholder. Used effectively, this can greatly enhanced your app’s user experience.

And finally, {x:Bind} is also capable to bind event handlers to events.

With classic binding, this was only possible by using ICommand to bind ViewModel’s methods to a Button click. If you wanted to bind to an event with no corresponding built-in Command property, you had to use a behavior and Interactions library from Blend SDK, usually you had to use EventToCommand behavior from MVVM libraries like MVVMLight.

One important thing to note also is that while classic binding uses the property DataContext as a root source for evaluating binded paths, Compiled Binding on the other hand directly references the root control in which it is used. For example, when using compiled binding in a page like MainPage, {x:Bind HelloWorld} will reference MainPage.HelloWorld. A field, a property or a method named HelloWorld must exist on MainPage and must be public. This also works when using compiled binding in a UserControl.

We’ll see in the next section a more complete comparison between {x:Bind} and {Binding}.

NB: Compiled Binding is only available for Windows 10 Universal apps (UWP). There is actually no plan to port it to WPF or Windows 8 apps in the future.

 

{Binding} versus {x:Bind}

Here’s a non-exhaustive list of differences between classic binding and compiled binding:

Classic Binding Compiled Binding
Creation Runtime Compile-time
Syntax {Binding LastName} {x:Bind LastName}
Root path context DataContext Root control (Page, UserControl, etc.)
Default mode OneWay OneTime
Invalid path Silently output an error in the console at runtime Build error
INotifyPropertyChanged
INotifyCollectionChanged
Supported Supported
Converters Supported Supported
Duck typing Supported Not supported
Dynamic creation (in code behind) Supported Not supported

Compiled Binding is missing some features from classic binding like Source, UpdateSourceTrigger, TemplatedParent, etc. If you really need these features, you should stick with classic binding when necessary.

RelativeSource=Self is a special case, the keyword itself is missing in compiled bindings but you just need to rewrite your binding because {x:Bind} has access to the root control instance and so has access to every named control in that root control.

RelativeSource with classic binding:

<TextBlock x:Name="TestClassicBinding" Text="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Name}" />

RelativeSource with compiled binding:

<TextBlock x:Name="TestCompiledBinding" Text="{x:Bind TestCompiledBinding.Name}" />

For a more complex use like binding to an unknown ancestor, stick with classic binding and RelativeSource.
 

Can I use both Compiled Binding and Classic Binding in a single project?

Of course you can!

As I said earlier, {x:Bind} only notifies the compiler to add some logic to handle passing a data to the UI that does not need usage of reflection at runtime like {Binding}.

Classic Binding is still available for UWP apps and is sometimes needed to achieve something Compiled Binding does not support such as Duck Typing, where you just know the property names but don’t know about the source object’s type (example : Property « Age » of classes Person and Wine).

It’s welcome when porting existing Windows 8 apps to Windows 10.

You can even use both bindings on a single control:

<TextBlock Text="{x:Bind Person.LastName}" Foreground="{Binding LastNameForegroundColor}" />

But Compiled Binding is currently only available for Universal Windows Platform projects.
 

When should I use Compiled Binding over Classic Binding?

Well, mostly anytime you can.

It really is a great way to enhance your app’s performance and simplify it a little (ICommand no more necessary) while remaining as easy to use as classic binding and as a bonus, troubleshooting becomes easier thanks to compile-time check of your paths!

Classic Binding is still there for you to use. It’s useful when you’re porting a previous Windows 8 app to Windows 10, or when you need advanced features only achievable without knowing the binded type at compile-time (for example, when you are dynamically loading XAML in your app or when your DataTemplate can be used with multiple types not having necessarily a common ancestor)
 

Binding to data

That’s all for introduction on compiled binding.
Head to « Part 1: Binding to data » to learn about how to use compiled binding with data.

Sécurité dynamique dans les cubes SSAS avec SQL Server 2012

Avec l’ouverture des données Power BI Self-Service vers les utilisateurs (vu dans plusieurs de mes missions) les métiers veulent gérer eux même les droits ou périmètres sur de nombreux utilisateurs finaux (>1000).

En effet dans certains domaines, nous avons une forte contrainte de confidentialité des données contenues dans les cubes SSAS. Les juridictions qui doivent s’appliquer peuvent être changées avec des cadences variables allant de la journée, à des cadences inférieures (temps réel). Pour cela, l’ensemble de la sécurité mise en œuvre est stocké dans la source de données du cube, qui détermine qui peut voir quoi.

A travers cet article, nous allons voir comment rendre dynamique une sécurité de cube SSAS basée sur l’appel à une procédure stockée.

Lire la suite

Gérer la mobilité des internes sur SharePoint (et autres), avec Azure AD Application Proxy

Dans un contexte de mobilité et BYOD, on désire de plus en plus ouvrir l’accès aux ressources « on premise » en dehors de l’entreprise. Si ADFS reste la référence pour l’ouverture aux externes, l’équipe Azure de MS a développé récemment un proxy applicatif permettant de se connecter en SSO  sans mise en place d’infrastructure ou reconfiguration de l’application « on premise ».

Votre application (ici un portail SharePoint) est tout simplement publiée comme une APP sur votre portail 365. L’authentification est transparente, en interne comme en mobilité.

On peut, bien sur, panacher avec ADFS pour les « vrais » externes qui n’auraient pas de compte dans un AD approuvé.

Le Principe

Dans le cas d’un utilisateur externe, on ne peut pas recourir à l’authentification intégrée sans VPN, et on recourt généralement à ADFS :

auth1

Si l’utilisateur externe (ou en mobilité) est référencé dans un annuaire AD, il existe une alternative à ADFS, présentée dans le cadre de ce post :

auth2

On évite ainsi :

  • De déployer ADFS
  • De recourir à un formulaire d’authentification ou autre custom provider

Le pré-requis est d’avoir synchronisé les utilisateurs avec notre tenant 365. On centralise alors l’authentification sur le tenant, et cette identitée « online » pourra être convertie en SSO en une identité interne via ce proxy applicatif.

Par exemple, dans le cas de l’authentification windows intégrée, « eissaly@mcnext.com » peut être utilisé comme « MCNEXT\Emmanuel.issaly »

Configuration 365

Si votre annuaire est déjà synchronisé avec azure AD (c’est un prérequis), Vous pouvez sauter ce chapitre. Sinon, créez un tenant Office 365 de test (un tenant de dev MSDN suffit)

image007

Créez une adresse admin facile à mémoriser, ici j’ai pris admin@eissaly.onmicrosoft.com

Sur ce tenant « eissaly », allez activer Azure AD par la tuile d’admin :

image008

Vous devez synchroniser les utilisateurs de votre domaine local avec un domaine online. Dans mon cas, mcnext.com étant déjà pris, j’ai ajouté un suffixe UPN « @clouddetest.fr » à mon AD de tests sp2013.local. Emmanuel ISSALY est alors identifié par SP2013\eissaly *ou* eissaly@clouddetest.fr.

Pour déclarer et vérifier le domaine clouddetest.fr dans azure, allez dans « Domains » du tenant 365 :

image009

Une fois le domaine vérifié, on peut lancer la synchronisation d’un serveur quelconque de notre lab avec ADCONNECT. C’est en fait un FIM customisé (au sens qu’il fonctionne correctement). Il vous faudra le compte admin 365 et le compte admin du domaine local.

Licences

Pour que l’application proxy fonctionne, il faut une licence Basic ou Premium AAD pour chaque utilisateur.
Activez le premium trial, ce qui vous donnera 100 licences.

image012

Publication de l’application SharePoint

Publication azure

 Nous allons publier notre SharePoint on prem comme une APP dans 365 :
Allons dans « Applications » de notre Azure AD, et faisons « ADD »

image013

image014

Puis s’offre à nous l’option de télécharger ce nouveau connecteur :

image015

Déployez-le sur un serveur 2012 R2 qui a accès à internet. Le serveur de synchro qui fait déjà AD connect est une bonne destination pour lui !

Suite à l’activation de ce connecteur, on a d’autres options dans la configuration de notre application :

1.- Une URL publique générique, ou l’adresse publique de votre domaine :

image017

image018

2. et la patte interne, en windows intégré :

image019

à noter que l’équipe azure AD travaille sans cesse à proposer de nouveau mappings, et l’on peut même maintenant convertir l’identité online à une identité non windows (via la délégation Kerberos)

Configuration HTTPS / Kerberos

Pour que cela marche, il faut quand même quelques contraintes, en l’occurrence une délégation contrainte Kerberos (KCD)

  1. Créer le SPN du portail (nom court nom long et compte de pool d’appli)

setspn –S http/portal sp_app

setspn –S http/portal.clouddetest.fr sp_app

2. Autoriser la délégation KCD sur le serveur qui héberge le connecteur :

Sur un contrôleur de domaine, Propriétés sur l’ordinateur, onglet délégation, autoriser la délégation :

image020image021

Puis ajoutez le SPN (on le trouve par le compte de pool)

image022

Vous devriez à présent obtenir un ticket kerberos en appelant votre site SharePoint.
Attention, il faut que le DNS appellé soit une IP (A record), pas un alias !

Synthèse

Le site SharePoint étant déclaré sur le tenant, on peut y accèder par un clic de tout périphérique connecté à Internet :

image023

De ce fait, que l’on soit à l’intérieur du LAN, ou d’un appareil mobile (ici Chrome + Android) connecté à office online, l’expérience utilisateur est maintenant la même, quelque soit l’environnement
(pas de prompt, Windows intégré dans notre cas)

image025

 Comment ça marche

Cf https://msdn.microsoft.com/en-us/library/azure/dn879065.aspx

image026

  1. L’utilisateur tape l’url du site SharePoint
  2. AAD proxy fait de la pré-auth : si vous êtes déjà connecté online, on obtient un jeton, sinon il vous prompte pour votre profil online.
  3. Dans tous les cas, le jeton obtenu est envoyé au proxy.
  4. Le connecteur extrait du jeton l’UPN (lidentifiant utilisateur)
  5. Le connecteur fait une demande de jeton Kerberos de la part de l’utilisateur
  6. Si la delegation est autorisée, le jeton est émis.
  7. Le connecteur envoie alors la requete et son jeton comme si on était “interne »
  8. La page est renvoyée au navigateur

Il est également possible de customiser le ticket kerberos pour que le login arrivant sur l’application ne soit pas l’email, ou soit un login différent du login online (typiquement pour se connecter à un système non Windows) :

image027

Sur ce schéma, je me connecte entant que joe@contoso.com à 365, mais j’arrive en tant que Contoso\joed sur l’application ciblée par ce connecteur.

Hey Cortana, do you speak JavaScript?

In this article I will try to describe every steps to use Cortana with your JavaScript UWP app.

The first step is to create an xml file that represents the Voice Command Definition :

<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
  <CommandSet xml:lang="fr-fr" Name="VDM_fr-fr">
    <CommandPrefix> VDM, </CommandPrefix>
    <Example> Affiche les dernières VDM </Example>
    
    <Command Name="showlast">
      <Example> Affiche les dernières VDM </Example>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> Affiche [les] dernières </ListenFor>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> Affiche [mes] dernières </ListenFor>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> Ouvre [les] dernières </ListenFor>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> montre [moi] [les] dernières </ListenFor>
      <Feedback> affichage des dernières VDM </Feedback>
      <Navigate />
    </Command>
    <Command Name="showcategorie">
      <Example> Affiche les VDM de travail</Example>
      <ListenFor RequireAppName="ExplicitlySpecified"> ouvre les {builtin:AppName} [de] {cat}</ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified"> affiche les {builtin:AppName} [de] {cat}</ListenFor>
      <Feedback> ouverture des VDM de {cat}</Feedback>
      <Navigate />
    </Command>

    <PhraseList Label="cat">
    </PhraseList>
  </CommandSet>
  <CommandSet xml:lang="en-us" Name="VDM_en-us">
    <CommandPrefix> FML </CommandPrefix>
    <Example> Show me the latest </Example>

    <Command Name="showlast">
      <Example> Show me the latest </Example>
      <ListenFor RequireAppName="AfterPhrase"> show [me] the latest </ListenFor>
      <ListenFor RequireAppName="AfterPhrase"> open the latest </ListenFor>
      <ListenFor RequireAppName="AfterPhrase"> display the latest </ListenFor>
      <Feedback>  display of the last FML</Feedback>
      <Navigate />
    </Command>

    <Command Name="showcategorie">
      <Example> Displays the FML of love </Example>
      <ListenFor RequireAppName="ExplicitlySpecified"> Opens the  {builtin:AppName} [of] {cat}</ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified"> Displays the {builtin:AppName} [of] {cat}</ListenFor>
      <Feedback> opening FML of {cat}</Feedback>
      <Navigate />
    </Command>

    <PhraseList Label="cat">
    </PhraseList>
  </CommandSet>

</VoiceCommands>
  • In this file the root element is the VoiceCommands Element, it’s contains a list of commandSet elements. Each commandSet is for a language.
    • An commandSet contains a list of command (and others things …)
      • A command is a “command” and contains an example, and multiple elements of ListenFor, a feedback element, and an instruction element (navigate in the first sample) that explicitly specifies that this command will navigate to your app.
        • ListenFor is the command phrase, it has a RequireAppName attribute that specifies where the app name can appear in the voice command.
      • A PhraseList that contains multiple item, each Item specifies a word or phrase that can be recognized to initiate the command that references the PhraseList (optional). You can optionnaly load dynamically a list of items from your code.

You have to be very careful, when you write this file! If you don’t respect the structure or If you miss an element, the Cortana API will fall in error without any information*.

The final step.
Instantiate your new XML file of VCD, in your JavaScript code.

In this following code, I call initCortana function to initialize the VCD file using de VoiceCommandDefinitionManager API located in the Windows.ApplicationModel.VoiceCommands namespace.

You have to pass your xml file to the « installCommandDefinitionsFromStorageFileAsync » function. If everything it’s not OK the callback of the promise returns a error and you pass by:

console.error(‘error file vdmvoicecommands.xml’, er);

In this case: check and re check an re re re check your VCD file :)

If the file was initialized correctly, you could add a list of items to populate the phrase lists.



    var wap = Windows.ApplicationModel.Package;
    var voiceCommandManager = Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager;

    var initCortana = function (categories) {
        categories = categories || [];
        return wap.current.installedLocation.getFileAsync("vdmvoicecommands.xml").then(function (file) {
            return voiceCommandManager.installCommandDefinitionsFromStorageFileAsync(file);
        }, function (er) {
            console.error('error file vdmvoicecommands.xml', er);
        }).then(function () {
           var language = window.navigator.userLanguage || window.navigator.language;

            var commandSetName = "VDM_" + language.toLowerCase();
            var commansets = Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.installedCommandDefinitions;
            if (commansets.hasKey(commandSetName)) {
                var vcd = commansets.lookup(commandSetName);
                var phraseList = [];
                categories.forEach(function (c) {
                    phraseList.push(c.title);
                });
                return vcd.setPhraseListAsync("cat", phraseList).then(function () {
                    console.log("VCD loaded !");
                 }, function (er) {
                    console.error('error set phraseList', er);
                })
            } else {
                console.warning("VCD not installed yet?");
            }
        }, function (ee) {
            console.error("installCommandDefinitionsFromStorageFileAsync error", ee);
        });
    }

Now you have to handle the activation event that will get sent to your app, and parse arguments.

  app.addEventListener("activated", function (args) {
        var appLaunchVoiceCommand = activation.ActivationKind.voiceCommand || 16;
        if (args.detail.kind === appLaunchVoiceCommand) {
            return handleVoiceCommand(args);
        }
    });

The handleVoiceCommand function parse the args passed from the activated app event and do the navigation to the right place

    var app = WinJS.Application;
    var commands = {
        "showlast": function (commandresult) {
            return WinJS.Navigation.navigate(VDM.Pages.VDMList, { viewType: 'last', viewLabel: WinJS.Resources.getString('appbar_views_last') });
        },
        "showcategorie": function (commandresult) {
            var categorie = commandresult.semanticInterpretation.properties.cat[0];
            return WinJS.Navigation.navigate(VDM.Pages.VDMList, { viewType: categorie.toLowerCase(), viewLabel: categorie });
        }
    }
    var handleVoiceCommand = function(args) {
        if (args.detail && args.detail.detail) {
            var voicecommand = args.detail.detail[0];
            if (voicecommand) {
                var result = voicecommand.result;

                if (result) {
                    var commandname = result.rulePath ? result.rulePath[0] : '';
                    var properties = result.semanticInterpretation ? result.semanticInterpretation.properties : {};
                    console.log("voice activation (" + commandname + ") confidence: " + result.rawConfidence, result);
                    var cmd = commands[commandname];
                    if (cmd) {
                        return cmd(result).then(function () {
                            VDM.Utils.loadMainAds();
                        });
                    }
                }

            }
        }
    }
    app.addEventListener("activated", function (args) {
        var appLaunchVoiceCommand = activation.ActivationKind.voiceCommand || 16;
        if (args.detail.kind === appLaunchVoiceCommand) {
            return handleVoiceCommand(args);
        }
    });

Let’s talk more with the app (with appService)

If you need a deeper integration with Cortana, you could also « talk » with her using an app service.

An app service is a Background task that Cortana could call when you use a command. You will have to explicitely declare which service Cortana must call in your command file.

    <Command Name="getFML">
      <Example> tell me a FML </Example>
      <ListenFor RequireAppName="ExplicitlySpecified"> tell me a {builtin:AppName} </ListenFor>
      <Feedback> Here an FML </Feedback>
      <VoiceCommandService Target="FMLVoiceCommandService"/>
    </Command>

Now let’s implement the Application Service. You must add it to your application manifest by pointing to JavaScript file, and give it the name you use in the command file :

 <uap:Extension Category="windows.personalAssistantLaunch"/>
 <uap:Extension Category="windows.appService" StartPage="js/voiceCommandService.js">
    <uap:AppService Name="FMLVoiceCommandService"/>
 </uap:Extension>

Beware the visual studio appxmanifest editor, it removes this entry if anything changes in it (like a upgrade of version when you generate a new appx package) this bug will certainly be corrected in the update 1 of Visual Studio.

Now let’s create the javascript file and implement the service itself.

When you are using JavaScript App Services are a lot like independant web workers. You can import all the JS file you need to run your code by using importScripts

importScripts("/WinJS/js/base.js");
importScripts("/js/FML.API.js");

The service is loaded by cortana, so when is loaded the doWork function is called.
If the Windows.UI.WebUI.WebUIBackgroundTaskInstance.current.triggerDetails is an instance of Windows.ApplicationModel.AppService.AppServiceTriggerDetails, we can get voice command used to launch this task and do things like:

  • Send an waiting response message
  • displays items
  • Send a final response message
var appService = Windows.ApplicationModel.AppService;
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
var details = backgroundTaskInstance.triggerDetails;
var deferral = backgroundTaskInstance.getDeferral();

if (details instanceof appService.AppServiceTriggerDetails) {
    voiceServiceConnection = voiceCommands.VoiceCommandServiceConnection.fromAppServiceTriggerDetails(details);
    voiceServiceConnection.addEventListener("voiceCommandCompleted", onVoiceCommandCompleted);

    voiceServiceConnection.getVoiceCommandAsync().then(function completed(voiceCommand) {

    // here you can check the voiceCommand, call an API (or read a file) and send messages to Cortana UI

            var userMessage = new voiceCommands.VoiceCommandUserMessage();
                    userMessage.spokenMessage = "I'm Cortana and I read this awesome message";
                    userMessage.displayMessage = "I'm Cortana and I read this awesome message";
            var response = voiceCommands.VoiceCommandResponse.createResponse(userMessage);
            return voiceServiceConnection.reportSuccessAsync(response);

    });
}

The displayMessage string must not exceed 256 character

And now, with this, you can ask Cortana: « hey cortana, tell me a FML »

#UWPHTML – using application insights in your Windows web applications

Publishing an application is a great experience. You really feel self-accomplishement when users provide good feedback (and ratings if you are Lucky). And then a few users reports errors but you can’t reproduce them. When your application is in the wild, you realize very quickly that you need something to get feedback from your app. Knowing what your users are doing with your application is also very valuable to help you focus efforts where you need to.

Without noticing you slipped from developping a hobby application to entering the world of analytics. You know, those little nasty snippets that your customers always asked you to put all around like Xiti or Google analytics.

Microsoft has it’s own solution for application analytics called Azure Application Insights. This tool has free and paid options depending on how long you store data, and the number of events you want to manage.

When you create a C# UWP application, Visual Studio has an option to integrate Application Insights for your project.

Unfortunately, you don’t have that same option when using UWP in HTML/JavaScript. In that case, you will have to do all plumbing manually. Microsoft provide a SDK for using Application Insight in JavaScript. It works well but this SDK is really oriented toward web applications, both in the sdk and in the structure of the Dashboard. Even worse, if you choose to type your application insights instance to a Windows application, some of the events (like errors…) does not show up in the Dashboard when sended with Javascript SDK.

For « Bring the popcorn« , it really is a Windows native application and we wanted to get the appropriate Dashboard and reporting. After some time spent with Fiddler comparing items sent to app insight from C#  and javascript, we narrowed down the différences in metadata.

We wrote small a wrapper for JavaScript sdk that adds those metadata and everything starts working fine.

This wrapper is published in WinJSContrib but we made it in such a way that it will work without WinJS or WinJSContrib.

Using application insights in your Windows Web Application is now very easy. You will first need to declare your application in application insights. When declaring your application, choose « Windows store application » for application type. When your instance is ready, go to it’s properties and get the « instrumentation key ». You will need this key in your application.

Now you are ready to integrate App Insights into your application. Go grab Application Insight Javascript SDK, and our wrapper, and add reference to them in your application.

In your application bootstrap code, you could now add something like this :


var appInsight = new WinJSContrib.WinRT.AppInsight({ instrumentationKey: "yourInstrumentationKey" });
appInsight.tracker.trackEvent("app start");

The wrapper will inject the appropriate metadata to have your events displayed in the Dashboard. It also registers to global « error » events, and send the corresponding errors to application insights.

If you are using WinJS, you could also have page navigation events for free :


appInsight.wrapWinJSNavigation();

If you want to see a real world example, you could check how we use this in Bring the popcorn.

#UWPHTML – Building Windows 10 web applications

Many people still ignores it, but since Windows 8 (and 8.1 for Windows Phone), you can build Windows native applications using HTML and JavaScript. Yes you read it correctly NATIVE applications. Those applications does NOT run through a webview but with a native HTML/JavaScript application shell called « wwahost ». Those applications are now called « Windows web applications ».

Windows 10 introduced a few enhancements to Windows web apps. They run with a different security context and on Microsoft Edge engine. There is also something called « project Westminster ». More simply, Westminster is « hosted applications », or applications that runs with content hosted on the internet but still have access to Windows APIs. You could find more about hosted apps on our blog, or obviously on Microsoft’s blog.

Windows web apps are fully parts of the new concept of Universal Windows Platform applications. It means that you could make applications using HTML/JavaScript for Windows desktop and tablet, but also for Windows 10 mobile, Xbox, Windows IoT, and the soon to come Hololens.

This post is the first of a serie where we will talk about various aspects of Universal Windows web apps using HTML and JavaScript. We will illustrate the different topics with a real application called « Bring the popcorn », a remote controller for a Kodi or Xbmc media server.

This application is open source, and available in the Windows store. It uses WinJS and WinJSContrib to provide a fast and fluid experience, using the latest features of Edge and Chakra engine (or at least those made available in web apps…).

Hope you will enjoy this serie !

Suivre

Recevez les nouvelles publications par mail.

Rejoignez 46 autres abonnés