Hi!
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.
The bindable property value should not be null.
The bindable property value is null.
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.
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:
x:Name
on the Entry with the behavior.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;
}
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:
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
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 ?