From 107ed5e545698a647b9cd1be22745a2c35aeebc4 Mon Sep 17 00:00:00 2001 From: adrianknight89 Date: Wed, 16 Nov 2016 02:24:21 -0600 Subject: [PATCH] BindingContext changes are called multiple times on app start (#470) * inherited binding context fix * add check for child binding context * Revert "add check for child binding context" This reverts commit 71952f39129cfedc2358a32100deb07bd32a3080. * unit tests --- .../BindableObjectUnitTests.cs | 84 +++++++++++++++++++ Xamarin.Forms.Core/BindableObject.cs | 7 +- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs index 7c4bac7a3..c46f7c0ed 100644 --- a/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs +++ b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs @@ -110,6 +110,90 @@ namespace Xamarin.Forms.Core.UnitTests Assert.Fail ("The BindingContextChanged event was not fired."); } + [Test] + public void BindingContextChangedOnce() + { + var count = 0; + + var mock = new MockBindable(); + mock.BindingContextChanged += (sender, args) => ++count; + + mock.BindingContext = new object(); + Assert.AreEqual(count, 1); + } + + [Test] + public void ParentAndChildBindingContextChanged() + { + int parentCount = 0, childCount = 0; + + var didNotChange = " BindingContext did not change."; + var changedMoreThanOnce = " BindingContext changed more than once."; + var changedWhenNoChange = " BindingContext was changed when there was no change in context."; + + var parent = new MockBindable(); + parent.BindingContextChanged += (sender, args) => { ++parentCount; }; + + var child = new MockBindable(); + child.BindingContextChanged += (sender, args) => { ++childCount; }; + + child.Parent = parent; + Assert.AreEqual(parentCount, 0, "Parent BindingContext was changed while parenting a child."); + Assert.AreEqual(childCount, 0, "Child" + changedWhenNoChange); + + child.BindingContext = new object(); // set manually + Assert.GreaterOrEqual(childCount, 1, "Child" + didNotChange); + Assert.AreEqual(childCount, 1, "Child" + changedMoreThanOnce); + Assert.AreEqual(parentCount, 0, "Parent" + changedWhenNoChange); + + parent.BindingContext = new object(); + Assert.GreaterOrEqual(parentCount, 1, "Parent" + didNotChange); + Assert.AreEqual(parentCount, 1, "Parent" + changedMoreThanOnce); + Assert.AreEqual(childCount, 1, "Child" + changedWhenNoChange); + + child.BindingContext = new object(); + Assert.GreaterOrEqual(childCount, 2, "Child" + didNotChange); + Assert.AreEqual(childCount, 2, "Child" + changedMoreThanOnce); + Assert.AreEqual(parentCount, 1, "Parent" + changedWhenNoChange); + } + + [Test] + public void ParentSetOnNullChildBindingContext() + { + var parent = new MockBindable(); + + var child = new MockBindable(); + child.BindingContextChanged += (sender, args) => { Assert.Fail("Child BindingContext was changed when there was no change in context."); }; + + child.Parent = parent; // this should not trigger binding context change on child since there is no change + parent.BindingContext = new object(); + parent.BindingContext = new object(); + } + + [Test] + public void ParentSetOnNonNullChildBindingContext() + { + var count = 0; + + var parent = new MockBindable(); + parent.BindingContextChanged += (sender, args) => { ++count; }; + + var child = new MockBindable(); + child.BindingContextChanged += (sender, args) => { ++count; }; + + child.BindingContext = new object(); // set manually + Assert.AreEqual(count, 1); + + child.Parent = parent; // this should not trigger binding context change because child binding was set manually + Assert.AreEqual(count, 1); + + parent.BindingContext = new object(); + Assert.AreEqual(count, 2); + + child.BindingContext = new object(); + Assert.AreEqual(count, 3); + } + [Test] [Description ("When the BindingContext changes, any bindings should be immediately applied.")] public void BindingContextChangedBindingsApplied() diff --git a/Xamarin.Forms.Core/BindableObject.cs b/Xamarin.Forms.Core/BindableObject.cs index fdf2afadf..217f4a942 100644 --- a/Xamarin.Forms.Core/BindableObject.cs +++ b/Xamarin.Forms.Core/BindableObject.cs @@ -98,6 +98,10 @@ namespace Xamarin.Forms return; object oldContext = bindable._inheritedContext; + + if (ReferenceEquals(oldContext, value)) + return; + if (bpContext != null && oldContext == null) oldContext = bpContext.Value; @@ -108,9 +112,6 @@ namespace Xamarin.Forms } else { - if (ReferenceEquals(oldContext, value)) - return; - bindable._inheritedContext = value; }