Skip to content

Instantly share code, notes, and snippets.

@Yortw
Created February 12, 2015 01:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Yortw/f4b1220296de0a1d53ce to your computer and use it in GitHub Desktop.
Save Yortw/f4b1220296de0a1d53ce to your computer and use it in GitHub Desktop.
A base class for Xamarin Behaviours that support bound properties but not instance sharing (one behaviour instance used against multiple associated objects simultaneously).
/// <summary>
/// Base class for creating Xamarin Forms behaviours that support bound properties on the behaviour, and as a neccesity do not support being shared across multiple associated objects.
/// </summary>
/// <typeparam name="T">The type of item this behaviour is bound to, must dervice from <see cref="Xamarin.Forms.BindableObject"/>.</typeparam>
/// <remarks>
/// <para>See http://forums.xamarin.com/discussion/comment/101682 and https://bugzilla.xamarin.com/show_bug.cgi?id=26521 for details on why <see cref="Xamarin.Forms.Behavior{T}"/> isn't suitable on it's own.</para>
/// <para>Note, behaviours using this base class cannot be reused (simultaneously) across multiple objects. For example you can't attach the same behaviour instance to two different <see cref="Xamarin.Forms.View"/> instances, you must create a seperate behaviour instance for each one. It is also possible for Xamarin forms to attempt instance sharing under some conditions (triggers, styles), so these behaviour are not suitable for those use cases.</para>
/// </remarks>
public abstract class InstancedBehavior<T> : Behavior<T> where T : BindableObject
{
/// <summary>
/// Returns the <see cref="Xamarin.Forms.BindableObject"/> this behaviour is associated with.
/// </summary>
protected T AssociatedObject { get; private set; }
/// <summary>
/// Sets the <see cref="AssociatedObject"/> and manages the binding context of the behaviour.
/// </summary>
/// <param name="bindable">An object dervied from <see cref="Xamarin.Forms.BindableObject"/> that is associated with this behaviour instance.</param>
protected override void OnAttachedTo(T bindable)
{
if (this.AssociatedObject != null && this.AssociatedObject != bindable)
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, "The behaviour {0} can only be used once per associated object. Do not use this behaviour in styles or triggers where Xamarin Forms attempts to share instances, or attempt to reuse an instance on multiple objects yourself.", this.GetType().FullName));
base.OnAttachedTo(bindable);
this.AssociatedObject = bindable;
if (bindable == null)
this.BindingContext = null;
else
{
bindable.BindingContextChanged += associatedObject_BindingContextChanged;
this.BindingContext = bindable.BindingContext;
}
}
/// <summary>
/// Clears the associated object and unhooks events used for managing the binding context.
/// </summary>
/// <param name="bindable">An object dervied from <see cref="Xamarin.Forms.BindableObject"/> that is associated with this behaviour instance.</param>
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
if (bindable != null)
bindable.BindingContextChanged -= this.associatedObject_BindingContextChanged;
this.AssociatedObject = null;
}
private void associatedObject_BindingContextChanged(object sender, EventArgs e)
{
var associatedObject = this.AssociatedObject;
if (associatedObject != null)
this.BindingContext = associatedObject.BindingContext;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment