Binding an event to a method, why does it work in UWP?
Asked Answered
T

2

7

UWP came with a new way of DataBinding, Compiled Binding, using the {x:Bind} markup extension, when I was discovering this new feature, I found out that we can actually bind an event to a method !

Example :

Xaml :

<Grid>
    <Button Click="{x:Bind Run}" Content="{x:Bind ButtonText}"></Button>
</Grid>

Code Behind :

private string _buttonText;

public string ButtonText
{
     get { return _buttonText; }
     set
         {
             _buttonText = value;
             OnPropertyChanged();
         }
}

public MainPage()
{
    this.InitializeComponent();
    ButtonText = "Click !";
}

public async void Run()
{
    await new MessageDialog("Yeah the binding worked !!").ShowAsync();
}

The result :

enter image description here

And since {x:Bind} bindings are evaluated at runtime and the compiler generates some files that represent that binding, so I went there to investigate what's going on, so in the MainPage.g.cs file (MainPage is the xaml file in question) I found this :

 // IComponentConnector

 public void Connect(int connectionId, global::System.Object target)
 {
      switch(connectionId)
      {
           case 2:
           this.obj2 = (global::Windows.UI.Xaml.Controls.Button)target;
                        ((global::Windows.UI.Xaml.Controls.Button)target).Click += (global::System.Object param0, global::Windows.UI.Xaml.RoutedEventArgs param1) =>
           {
               this.dataRoot.Run();
           };
                break;
           default:
                break;
      }
}

The compiler seems to know that it's a valid binding, moreover it creates the corresponding event handler, and it calls the concerned method inside.

That is great ! but why ?? A binding target should be a dependency property, not an event. The official documentation for {x:Bind} does mention this new feature, but doesn't explain why and how can a non dependency property be a target of binding, anyone who has a deep explanation for this ?

Tingley answered 3/2, 2016 at 21:48 Comment(1)
While the target property of a regular binding has to be a dependency property, I couldn't find any mention of this restriction in the {x:Bind} documentation. So could you give any reference for "A binding target should be a dependency property"?Printery
P
1

A binding target should be a dependency property

While this is true for a regular binding, it does not hold for the {x:Bind} markup extension.

So you can in fact have a non-dependency property like e.g.

public sealed partial class MyUserControl : UserControl
{
    public Color BackgroundColor
    {
        get { return ((SolidColorBrush)Background).Color; }
        set { Background = new SolidColorBrush(value); }
    }
}

as an {x:Bind} target like this:

<local:MyUserControl BackgroundColor="{x:Bind ViewModel.BgColor}" />

while

<local:MyUserControl BackgroundColor="{Binding ViewModel.BgColor}" />

would fail.

Printery answered 4/2, 2016 at 12:2 Comment(1)
Fair enough, Although the official documentation does say in the "Every binding involves these pieces" msdn.microsoft.com/en-us/library/windows/apps/mt210946.aspx that the binding target have to be a DependencyProperty without mentioning any exception for the new syntax, thx for clarifying !Tingley
T
3

Well, it's sort of the new feature of the "x:Bind" compiled binding.

https://msdn.microsoft.com/en-us/library/windows/apps/mt204783.aspx

Event binding is a new feature for compiled binding. It enables you to specify the handler for an event using a binding, rather than it having to be a method on the code behind. For example: Click="{x:Bind rootFrame.GoForward}".

For events, the target method must not be overloaded and must also:

  1. Match the signature of the event.
  2. OR have no parameters.
  3. OR have the same number of parameters of types that are assignable from the types of the event parameters.

I guess your scenario perfectly match item 2.

Tetracaine answered 4/2, 2016 at 2:19 Comment(0)
P
1

A binding target should be a dependency property

While this is true for a regular binding, it does not hold for the {x:Bind} markup extension.

So you can in fact have a non-dependency property like e.g.

public sealed partial class MyUserControl : UserControl
{
    public Color BackgroundColor
    {
        get { return ((SolidColorBrush)Background).Color; }
        set { Background = new SolidColorBrush(value); }
    }
}

as an {x:Bind} target like this:

<local:MyUserControl BackgroundColor="{x:Bind ViewModel.BgColor}" />

while

<local:MyUserControl BackgroundColor="{Binding ViewModel.BgColor}" />

would fail.

Printery answered 4/2, 2016 at 12:2 Comment(1)
Fair enough, Although the official documentation does say in the "Every binding involves these pieces" msdn.microsoft.com/en-us/library/windows/apps/mt210946.aspx that the binding target have to be a DependencyProperty without mentioning any exception for the new syntax, thx for clarifying !Tingley

© 2022 - 2024 — McMap. All rights reserved.