Assert.AreEqual ("Baz", label.Text);
}
+
+ class VM57081
+ {
+ string _foo;
+ public string Foo
+ {
+ get {
+ Count++;
+ return _foo;
+ }
+ set { _foo = value; }
+ }
+
+ public int Count { get; set; }
+ }
+
+ [Test]
+ // https://bugzilla.xamarin.com/show_bug.cgi?id=57081
+ public void BindingWithSourceNotReappliedWhenBindingContextIsChanged()
+ {
+ var bindable = new MockBindable();
+ var model = new VM57081();
+ var bp = BindableProperty.Create("foo", typeof(string), typeof(MockBindable), null);
+ Assume.That(model.Count, Is.EqualTo(0));
+ bindable.SetBinding(bp, new Binding { Path = "Foo", Source = model });
+ Assume.That(model.Count, Is.EqualTo(1));
+ bindable.BindingContext = new object();
+ Assert.That(model.Count, Is.EqualTo(1));
+ }
+
+ [Test]
+ // https://bugzilla.xamarin.com/show_bug.cgi?id=57081
+ public void BindingWithSourceNotReappliedWhenParented()
+ {
+ var view = new ContentView();
+ var model = new VM57081();
+ Assume.That(model.Count, Is.EqualTo(0));
+ view.SetBinding(BindableObject.BindingContextProperty, new Binding { Path = "Foo", Source = model });
+ Assume.That(model.Count, Is.EqualTo(1));
+ var parent = new ContentView { BindingContext = new object() };
+ parent.Content = view;
+ Assert.That(model.Count, Is.EqualTo(1));
+ }
}
}
\ No newline at end of file
bindable._inheritedContext = value;
}
- bindable.ApplyBindings();
+ bindable.ApplyBindings(skipBindingContext:false, fromBindingContextChanged:true);
bindable.OnBindingContextChanged();
}
protected void ApplyBindings()
{
- ApplyBindings(false);
+ ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
}
protected virtual void OnBindingContextChanged()
}
}
- void ApplyBindings(bool skipBindingContext)
+ internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
{
var prop = _properties.ToArray();
for (int i = 0, propLength = prop.Length; i < propLength; i++) {
if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
continue;
- binding.Unapply();
- binding.Apply(BindingContext, this, context.Property);
+ binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
+ binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
}
}
static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
bindable._inheritedContext = null;
- bindable.ApplyBindings(true);
+ bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged:true);
bindable.OnBindingContextChanged();
}
_expression.Apply(fromTarget);
}
- internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty)
+ internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
{
object src = _source;
- base.Apply(src ?? newContext, bindObj, targetProperty);
+ var isApplied = IsApplied;
+
+ base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
+
+ if (src != null && isApplied && fromBindingContextChanged)
+ return;
object bindingContext = src ?? Context ?? newContext;
if (_expression == null && bindingContext != null)
return base.GetTargetValue(value, sourcePropertyType);
}
- internal override void Unapply()
+ internal override void Unapply(bool fromBindingContextChanged = false)
{
- base.Unapply();
+ if (Source != null && fromBindingContextChanged && IsApplied)
+ return;
+
+ base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
if (_expression != null)
_expression.Unapply();
IsApplied = true;
}
- internal virtual void Apply(object context, BindableObject bindObj, BindableProperty targetProperty)
+ internal virtual void Apply(object context, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
{
IsApplied = true;
}
return SynchronizedCollections.TryGetValue(collection, out synchronizationContext);
}
- internal virtual void Unapply()
+ internal virtual void Unapply(bool fromBindingContextChanged = false)
{
IsApplied = false;
}
if (Platform != null)
child.Platform = Platform;
- child.ApplyBindings();
+ child.ApplyBindings(skipBindingContext: false, fromBindingContextChanged:true);
if (ChildAdded != null)
ChildAdded(this, new ElementEventArgs(child));
_expression.Apply(fromTarget);
}
- internal override async void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty)
+ internal override async void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
{
var view = bindObj as Element;
if (view == null)
throw new InvalidOperationException();
- base.Apply(newContext, bindObj, targetProperty);
+ base.Apply(newContext, bindObj, targetProperty, fromBindingContextChanged);
Element templatedParent = await TemplateUtilities.FindTemplatedParentAsync(view);
ApplyInner(templatedParent, bindObj, targetProperty);
return base.GetTargetValue(value, sourcePropertyType);
}
- internal override void Unapply()
+ internal override void Unapply(bool fromBindingContextChanged = false)
{
- base.Unapply();
+ base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
if (_expression != null)
_expression.Unapply();
}
// Applies the binding to a new source or target.
- internal override void Apply(object context, BindableObject bindObj, BindableProperty targetProperty)
+ internal override void Apply(object context, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
{
_targetProperty = targetProperty;
var source = Source ?? Context ?? context;
+ var isApplied = IsApplied;
-#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
- base.Apply(source, bindObj, targetProperty);
+ if (Source != null && isApplied && fromBindingContextChanged)
+ return;
+ base.Apply(source, bindObj, targetProperty, fromBindingContextChanged);
+
+#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
BindableObject prevTarget;
if (_weakTarget.TryGetTarget(out prevTarget) && !ReferenceEquals(prevTarget, bindObj))
throw new InvalidOperationException("Binding instances can not be reused");
return value;
}
- internal override void Unapply()
+ internal override void Unapply(bool fromBindingContextChanged = false)
{
+ if (Source != null && fromBindingContextChanged && IsApplied)
+ return;
+
#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
- base.Unapply();
+ base.Unapply(fromBindingContextChanged:fromBindingContextChanged);
#endif
if (_handlers != null)
Unsubscribe();
_expression.Apply(fromTarget);
}
- internal override async void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty)
+ internal override async void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged)
{
var view = bindObj as VisualElement;
if (view == null)
throw new InvalidOperationException();
- base.Apply(newContext, bindObj, targetProperty);
+ base.Apply(newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
Element dataSourceParent = await FindDataSourceParentAsync(view);
return base.GetTargetValue(value, sourcePropertyType);
}
- internal override void Unapply()
+ internal override void Unapply(bool fromBindingContextChanged = false)
{
- base.Unapply();
+ base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
var dataSourceProviderer = (IDataSourceProvider)_dataSourceRef?.Target;
dataSourceProviderer?.UnmaskKey(_path);
using Xamarin.Forms;
using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
[SetUp]
public void Setup ()
{
+ Device.PlatformServices = new MockPlatformServices();
Bz34037Converter0.Invoked = 0;
Bz34037Converter1.Invoked = 0;
}
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ Application.Current = null;
+ }
+
+
[TestCase(true)]
[TestCase(false)]
public void ConverterParameterOrderDoesNotMatters (bool useCompiledXaml)
{
var layout = new Bz34037 (useCompiledXaml);
- Assert.AreEqual (2, Bz34037Converter0.Invoked);
-// Assert.AreEqual (2, Bz34037Converter1.Invoked);
+ Assert.AreEqual (1, Bz34037Converter0.Invoked);
+ Assert.AreEqual (1, Bz34037Converter1.Invoked);
Assert.AreEqual (typeof(string), Bz34037Converter0.Parameter);
-// Assert.AreEqual (typeof(string), Bz34037Converter1.Parameter);
+ Assert.AreEqual (typeof(string), Bz34037Converter1.Parameter);
+ Assert.That(layout.s0.IsToggled, Is.True);
+ Assert.That(layout.s1.IsToggled, Is.True);
}
}
}