Xamarin.forms: Behavior binding context is always null

Created on 2 May 2018  路  6Comments  路  Source: xamarin/Xamarin.Forms

Hi!

Description

I found out that if I create a custom behavior and I bind properties in it, those properties values are always null, because the binding context of the behavior is also null.

Steps to Reproduce

  1. Create a custom behavior with bindable properties
  2. Use this behavior in your code, and bind a property to the bindable property of the behavior
  3. The bindable property value is always null

Expected Behavior

The bindable property value should not be null.

Actual Behavior

The bindable property value is null.

Basic Information

  • Version with issue:

    • Latest stable on NuGet.org (2.5.1.444934)

    • Latest stable on MyGet (2.6.0.251661)

    • Latest nightly on MyGet (3.1.0.444738-nightly)

  • Last known good version: None
  • IDE: Visual Studio Pro 2017 15.6.7

Reproduction Link

The following project reproduce the problem.
Compile the project, run the app. Enter a pin code in the entry box. If the pin code entered is 4242, the text should change to "OK!".
The actual behavior we have is a crash because the bindable property CustomCommand is null.

BehaviorBindingBugRepro.zip

Note that I already tried to set the binding context of the behavior like in the following code, but I still have the issue.

                <Entry.Behaviors>
                    <behaviors:CustomBehavior BindingContext="{Binding .}"
                                              TextLenght="4"
                                              CustomCommand="{Binding ValidationCommand}" />
                </Entry.Behaviors>

Thank you!

Edit:
I just found a workaround to make it work while waiting for the fix:

  • Set a x:Name on the Entry with the behavior
  • In the .xaml.cs file of the page with the entry, override the OnAppearing method and add the following code:
        protected override void OnAppearing()
        {
            base.OnAppearing();
            // Replace PinCodeEntry with the name you wrote in x:Name element
            foreach (var behavior in this.PinCodeEntry.Behaviors)
                behavior.BindingContext = this.BindingContext;
        }
invalid

Most helpful comment

This is my mistake.

Mine.

Only mine.

I can't even remember what I was thinking while doing it, but inheriting Behaviors from BindableObject is a choice I regret almost once a week since then.

Behaviors instances are meant to be shared (and applied through styles). The BindingContext doesn't make any sense in that scenario.

What you have to do is override OnAttachedTo (and detach as well), and if you need the binding context, get the BindingContext of the targetObject. And, as in your case the behavior isn't shared, you should be just fine.

I'm so sorry.

Can I go back to hiding ?

All 6 comments

This is my mistake.

Mine.

Only mine.

I can't even remember what I was thinking while doing it, but inheriting Behaviors from BindableObject is a choice I regret almost once a week since then.

Behaviors instances are meant to be shared (and applied through styles). The BindingContext doesn't make any sense in that scenario.

What you have to do is override OnAttachedTo (and detach as well), and if you need the binding context, get the BindingContext of the targetObject. And, as in your case the behavior isn't shared, you should be just fine.

I'm so sorry.

Can I go back to hiding ?

No problem!
Just a lack of documentation maybe?
Anyway, thank you for the solution :)

I was just struggling with the same problem as @nicolas-garcia. There is a BindableBase<T> base class for behaviors on the net, which does exactly what @StephaneDelcroix described: It sets the BindingContext of the target object (T) to the behavior as soon as the BindingContext is available.

One implementation of BindableBase<T> can be found here but there are hundreds of it on github...

@thomasgalliker don't. Behaviors can be shared (when set from Style). this is why they don't have a context

Ups. Correct me if I'm wrong:

  • When I set Behaviors via Styles, it reuses the same Behavior instance?
  • When I set Behaviors directly on controls (e.g. Entry), it creates a new Behavior instance for each application?

I use a dependency property on a behavior in order to limit the max text length of an Entry. In the following case I'm binding the viewmodel property NameMaxLength to the behaviort:

<xControls:ValidatableEntry
    Text="{Binding Name, Mode=TwoWay}">
    <xControls:ValidatableEntry.Behaviors>
        <behaviors:MaxLengthTextBehavior MaxLength="{Binding NameMaxLength}" />
    </xControls:ValidatableEntry.Behaviors>
</xControls:ValidatableEntry>

Edit: Ok, I'm just too stupid for this: Entry (->InputView) exposes a MaxLength property which I can use to bind to. My mistake :)

Ups. Correct me if I'm wrong:

  • When I set Behaviors via Styles, it reuses the same Behavior instance?
  • When I set Behaviors directly on controls (e.g. Entry), it creates a new Behavior instance for each application?

you're correct

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xabre picture xabre  路  3Comments

Hudhud picture Hudhud  路  3Comments

MartinWegner picture MartinWegner  路  3Comments

joseluisct picture joseluisct  路  3Comments

simontocknell picture simontocknell  路  3Comments