Le Post Infeeny

Les articles des consultants et experts Infeeny

#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« .

3 réponses à “#UWPXAML – Compiled Binding – Binding to events

  1. cvb 1 janvier 2016 à 20 08 09 01091

    the samples for UWP do not contain a relaycommand class with a generic, why not?

    • Timothé LARIVIERE 4 janvier 2016 à 7 07 44 01441

      Hi
      RelayCommand isn’t built into the .NET Framework, each library makes its own implementation of the ICommand interface (MVVMLight for instance has a generic RelayCommand).

      You’ll see mostly non-generic uses of ICommand rather than generic ones as most of the time, there is no need for a CommandParameter.
      And if, once in a while, there is a need for CommandParameter, it just gets easier to cast the parameter by yourself rather than creating a whole new class for it.
      That might be the reason why the UWP samples don’t contain a generic RelayCommand.

  2. Anton 21 octobre 2016 à 19 07 19 101910

    Thank You for your describe this really wonderful method about x:Bind. In my cause I have some question that I meet on my way.
    1. Why I should use Public modifier?
    2. When I use this stroke(public void OnButtonClicked(object sender, EventArgs args)) I had an error like this (the name args does not exist in the current context) and decision was replace the « args » on « e » and then comile have successful. Then when I replace back on « args » compiling have successful result yet…some strange for me.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :