-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Behavior binding context is always null #2581
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 I'm so sorry. Can I go back to hiding ? |
No problem! |
I was just struggling with the same problem as @nicolas-garcia. There is a One implementation of |
@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 :) |
you're correct |
I have a hack using Behavior for this. For me it works for iOS and Android. Other platform have not tried. In XAML set binding for <CarouselView
ItemsSource="{Binding Items}">
<CarouselView.ItemTemplate>
<DataTemplate>
<YourView />
</DataTemplate>
</CarouselView.ItemTemplate>
<CarouselView.Behaviors>
<hacks:AndroidCarouselFixBehavior CurrentItem="{Binding CurrentItem, Mode=TwoWay}"/>
</CarouselView.Behaviors>
</CarouselView> Add this to your project namespace MyProject.Hacks
{
public sealed partial class AndroidCarouselFixBehavior : Behavior<CarouselView>
{
public static readonly BindableProperty CurrentItemProperty =
BindableProperty.Create(nameof(CurrentItem), typeof(object), typeof(AndroidCarouselFixBehavior),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnCurrentItemChanged);
public object CurrentItem
{
get => (object)GetValue(CurrentItemProperty);
set => SetValue(CurrentItemProperty, value);
}
private static partial void OnCurrentItemChanged(BindableObject bindable, object oldValue, object newValue);
protected override void OnAttachedTo(BindableObject bindable)
{
base.OnAttachedTo(bindable);
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}
protected override void OnDetachingFrom(BindableObject bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
BindingContext = null;
}
private void Bindable_BindingContextChanged(object sender, EventArgs e)
{
BindingContext = (sender as BindableObject).BindingContext;
}
}
#if !ANDROID
public sealed partial class AndroidCarouselFixBehavior : Behavior<CarouselView>
{
private static partial void OnCurrentItemChanged(BindableObject bindable, object oldValue, object newValue)
{
}
protected override void OnAttachedTo(CarouselView bindable)
{
base.OnAttachedTo(bindable);
bindable.SetBinding(CarouselView.CurrentItemProperty, new Binding(CurrentItemProperty.PropertyName, source: this));
}
protected override void OnDetachingFrom(CarouselView bindable)
{
base.OnDetachingFrom(bindable);
bindable.RemoveBinding(CarouselView.CurrentItemProperty);
}
}
#endif
}
#if ANDROID
namespace MyProject.Hacks
{
public sealed partial class AndroidCarouselFixBehavior
{
CarouselView Bindable { get; set; }
private static partial void OnCurrentItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = bindable as AndroidCarouselFixBehavior;
var carousel = behavior?.Bindable;
var source = carousel?.ItemsSource;
var item = behavior.CurrentItem;
if (source == null || item == null || carousel.CurrentItem == item)
return;
var index = Array.IndexOf(source.Cast<object>().ToArray(), item);
if (index < 0)
return;
carousel.ScrollTo(index);
}
protected override void OnAttachedTo(CarouselView bindable)
{
base.OnAttachedTo(bindable);
Bindable = bindable;
bindable.CurrentItemChanged += Bindable_CurrentItemChanged;
}
protected override void OnDetachingFrom(CarouselView bindable)
{
base.OnDetachingFrom(bindable);
Bindable = null;
bindable.CurrentItemChanged -= Bindable_CurrentItemChanged;
}
private void Bindable_CurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
{
if (e.CurrentItem is null)
return;
CurrentItem = e.CurrentItem;
}
}
}
#endif |
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
Expected Behavior
The bindable property value should not be null.
Actual Behavior
The bindable property value is null.
Basic Information
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.
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 theOnAppearing
method and add the following code:The text was updated successfully, but these errors were encountered: