summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs')
-rw-r--r--Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs
new file mode 100644
index 00000000..7c4bac7a
--- /dev/null
+++ b/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs
@@ -0,0 +1,1326 @@
+using System;
+using System.Globalization;
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Core.UnitTests
+{
+ [TypeConverter (typeof(ToBarConverter))]
+ internal class Bar
+ {
+
+ }
+
+ internal class Baz
+ {
+
+ }
+
+ internal class MockBindable
+ : VisualElement
+ {
+ public static readonly BindableProperty TextProperty = BindableProperty.Create<MockBindable, string> (
+ b => b.Text, "default", BindingMode.TwoWay);
+
+ public string Text
+ {
+ get { return (string)GetValue (TextProperty); }
+ set { SetValue (TextProperty, value); }
+ }
+
+ public string Foo { get; set; }
+
+ public int TargetInt { get; set; }
+
+ public static readonly BindableProperty BarProperty =
+ BindableProperty.Create<MockBindable, Bar> (w => w.Bar, default(Bar));
+
+ public Bar Bar {
+ get { return (Bar)GetValue (BarProperty); }
+ set { SetValue (BarProperty, value); }
+ }
+
+ public static readonly BindableProperty BazProperty =
+ BindableProperty.Create<MockBindable, Baz> (w => w.Baz, default(Baz));
+
+ [TypeConverter (typeof (ToBazConverter))]
+ public Baz Baz {
+ get { return (Baz)GetValue (BazProperty); }
+ set { SetValue (BazProperty, value); }
+ }
+
+ public static readonly BindableProperty QuxProperty =
+ BindableProperty.Create<MockBindable, Baz> (w => w.Qux, default(Baz));
+
+ public Baz Qux {
+ get { return (Baz)GetValue (QuxProperty); }
+ set { SetValue (QuxProperty, value); }
+ }
+ }
+
+ internal class ToBarConverter : TypeConverter
+ {
+ public override object ConvertFrom (System.Globalization.CultureInfo culture, object value)
+ {
+ return new Bar ();
+ }
+ }
+
+ internal class ToBazConverter : TypeConverter
+ {
+ public override object ConvertFrom (System.Globalization.CultureInfo culture, object value)
+ {
+ return new Baz ();
+ }
+ }
+
+ [TestFixture]
+ public class BindableObjectUnitTests : BaseTestFixture
+ {
+ [SetUp]
+ public void Setup()
+ {
+ Device.PlatformServices = new MockPlatformServices ();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
+ [Test]
+ public void BindingContext()
+ {
+ var mock = new MockBindable();
+ Assert.IsNull (mock.BindingContext);
+
+ object obj = new object();
+ mock.BindingContext = obj;
+ Assert.AreSame (obj, mock.BindingContext);
+ }
+
+ [Test]
+ public void BindingContextChangedEvent()
+ {
+ var mock = new MockBindable();
+ mock.BindingContextChanged += (sender, args) => Assert.Pass();
+
+ mock.BindingContext = new object();
+
+ Assert.Fail ("The BindingContextChanged event was not fired.");
+ }
+
+ [Test]
+ [Description ("When the BindingContext changes, any bindings should be immediately applied.")]
+ public void BindingContextChangedBindingsApplied()
+ {
+ var mock = new MockBindable();
+ mock.SetBinding (MockBindable.TextProperty, new Binding ("."));
+ mock.BindingContext = "Test";
+
+ Assert.AreEqual ("Test", mock.GetValue (MockBindable.TextProperty));
+
+ mock.BindingContext = "Testing";
+
+ Assert.AreEqual ("Testing", mock.GetValue (MockBindable.TextProperty),
+ "Bindings were not reapplied to the new binding context");
+ }
+
+ [Test]
+ [Description ("When the BindingContext changes, the new context needs to listen for updates.")]
+ public void BindingContextChangedBindingsListening()
+ {
+ var mock = new MockBindable();
+ mock.SetBinding (MockBindable.TextProperty, new Binding ("Text"));
+
+ var vm = new MockViewModel();
+ mock.BindingContext = vm;
+
+ mock.BindingContext = (vm = new MockViewModel());
+
+ vm.Text = "test";
+
+ Assert.AreEqual ("test", mock.GetValue (MockBindable.TextProperty),
+ "The new ViewModel was not being listened to after being set");
+ }
+
+ [Test]
+ [Description ("When an INPC implementer is unset as the BindingContext, its changes shouldn't be listened to any further.")]
+ public void BindingContextUnsetStopsListening()
+ {
+ var mock = new MockBindable();
+ mock.SetBinding (MockBindable.TextProperty, new Binding ("Text"));
+
+ var vm = new MockViewModel();
+ mock.BindingContext = vm;
+
+ mock.BindingContext = null;
+
+ vm.Text = "test";
+
+ Assert.IsNull (mock.GetValue (Entry.TextProperty), "ViewModel was still being listened to after set to null");
+ }
+
+ [Test]
+ public void PropertyChanging()
+ {
+ var mock = new MockBindable();
+ mock.PropertyChanging += (sender, args) => {
+ Assert.AreEqual (MockBindable.TextProperty.PropertyName, args.PropertyName);
+ Assert.AreEqual (MockBindable.TextProperty.DefaultValue, mock.GetValue (MockBindable.TextProperty));
+ Assert.Pass();
+ };
+
+ mock.SetValue (MockBindable.TextProperty, "foo");
+
+ Assert.Fail ("The PropertyChanging event was not fired.");
+ }
+
+ [Test]
+ public void PropertyChangingSameValue()
+ {
+ const string value = "foo";
+
+ var mock = new MockBindable();
+ mock.SetValue (MockBindable.TextProperty, value);
+ mock.PropertyChanging += (s,e) => Assert.Fail();
+
+ mock.SetValue (MockBindable.TextProperty, value);
+
+ Assert.Pass();
+ }
+
+ [Test]
+ public void PropertyChangingDefaultValue()
+ {
+ var prop = BindableProperty.Create<MockBindable, string> (w => w.Foo, "DefaultValue");
+
+ var mock = new MockBindable();
+ mock.PropertyChanging += (s,e) => Assert.Fail();
+ mock.SetValue (prop, prop.DefaultValue);
+
+ Assert.Pass();
+ }
+
+ [Test]
+ public void PropertyChanged()
+ {
+ const string value = "foo";
+
+ var mock = new MockBindable();
+ mock.PropertyChanged += (sender, args) => {
+ Assert.AreEqual (MockBindable.TextProperty.PropertyName, args.PropertyName);
+ Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty));
+ Assert.Pass();
+ };
+
+ mock.SetValue (MockBindable.TextProperty, value);
+
+ Assert.Fail ("The PropertyChanged event was not fired.");
+ }
+
+ [Test]
+ public void PropertyChangedSameValue()
+ {
+ const string value = "foo";
+
+ var mock = new MockBindable();
+ mock.SetValue (MockBindable.TextProperty, value);
+ mock.PropertyChanged += (s,e) => Assert.Fail();
+
+ mock.SetValue (MockBindable.TextProperty, value);
+
+ Assert.Pass();
+ }
+
+ [Test]
+ public void PropertyChangedDefaultValue()
+ {
+ var prop = BindableProperty.Create<MockBindable, string> (w => w.Foo, "DefaultValue");
+
+ var mock = new MockBindable();
+ mock.PropertyChanged += (s,e) => Assert.Fail();
+
+ mock.SetValue (prop, prop.DefaultValue);
+
+ Assert.Pass();
+ }
+
+ [Test]
+ public void GetSetValue()
+ {
+ const string value = "foo";
+ var mock = new MockBindable();
+ mock.SetValue (MockBindable.TextProperty, value);
+
+ Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty));
+ }
+
+ [Test]
+ public void GetValueDefault()
+ {
+ var nulldefault = BindableProperty.Create<MockBindable, string> (w => w.Foo, null);
+ TestGetValueDefault (nulldefault);
+
+ var foodefault = BindableProperty.Create<MockBindable, string> (w => w.Foo, "Foo");
+ TestGetValueDefault (foodefault);
+ }
+
+ void TestGetValueDefault (BindableProperty property)
+ {
+ var mock = new MockBindable();
+ object value = mock.GetValue (property);
+ Assert.AreEqual (property.DefaultValue, value);
+ }
+
+ [Test]
+ public void SetValueInvalid()
+ {
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentNullException> (() => mock.SetValue ((BindableProperty)null, "null"));
+ }
+
+ [Test]
+ public void GetValueInvalid()
+ {
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentNullException> (() => mock.GetValue (null));
+ }
+
+ [Test]
+ public void ClearValueInvalid()
+ {
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentNullException> (() => mock.ClearValue ((BindableProperty)null));
+ }
+
+ [Test]
+ public void ClearValue()
+ {
+ const string value = "foo";
+ var mock = new MockBindable();
+ mock.SetValue (MockBindable.TextProperty, value);
+ Assert.AreEqual (value, mock.GetValue (MockBindable.TextProperty));
+
+ mock.ClearValue (MockBindable.TextProperty);
+ TestGetValueDefault (MockBindable.TextProperty);
+ }
+
+ [Test]
+ public void ClearValueTriggersINPC ()
+ {
+ var bindable = new MockBindable ();
+ bool changingfired = false;
+ bool changedfired = false;
+ bool changingdelegatefired = false;
+ bool changeddelegatefired = false;
+ var property = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), "foo",
+ propertyChanged: (b, o, n) => changeddelegatefired = true,
+ propertyChanging: (b, o, n) => changingdelegatefired = true
+ );
+ bindable.PropertyChanged += (sender, e) => { changedfired |= e.PropertyName == "Foo"; };
+ bindable.PropertyChanging += (sender, e) => { changingfired |= e.PropertyName == "Foo"; };
+
+ bindable.SetValue (property, "foobar");
+ changingfired = changedfired = changeddelegatefired = changingdelegatefired = false;
+
+ bindable.ClearValue (property);
+ Assert.True (changingfired);
+ Assert.True (changedfired);
+ Assert.True (changingdelegatefired);
+ Assert.True (changeddelegatefired);
+ }
+
+ [Test]
+ public void ClearValueDoesNotTriggersINPCOnSameValues ()
+ {
+ var bindable = new MockBindable ();
+ bool changingfired = false;
+ bool changedfired = false;
+ bool changingdelegatefired = false;
+ bool changeddelegatefired = false;
+ var property = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), "foo",
+ propertyChanged: (b, o, n) => changeddelegatefired = true,
+ propertyChanging: (b, o, n) => changingdelegatefired = true
+ );
+ bindable.PropertyChanged += (sender, e) => { changedfired |= e.PropertyName == "Foo"; };
+ bindable.PropertyChanging += (sender, e) => { changingfired |= e.PropertyName == "Foo"; };
+
+ bindable.SetValue (property, "foobar");
+ bindable.SetValue (property, "foo");
+ changingfired = changedfired = changeddelegatefired = changingdelegatefired = false;
+
+ bindable.ClearValue (property);
+ Assert.False (changingfired);
+ Assert.False (changedfired);
+ Assert.False (changingdelegatefired);
+ Assert.False (changeddelegatefired);
+ }
+
+ [Test]
+ public void SetBindingInvalid()
+ {
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentNullException> (() => mock.SetBinding (null, new Binding (".")));
+ Assert.Throws<ArgumentNullException> (() => mock.SetBinding (MockBindable.TextProperty, null));
+ }
+
+ [Test]
+ public void RemoveUnaddedBinding()
+ {
+ var mock = new MockBindable();
+ Assert.That (() => mock.RemoveBinding (MockBindable.TextProperty), Throws.Nothing);
+ }
+
+ [Test]
+ public void RemoveBindingInvalid()
+ {
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentNullException> (() => mock.RemoveBinding (null));
+ }
+
+ [Test]
+ public void RemovedBindingDoesNotUpdate()
+ {
+ const string newvalue = "New Value";
+ var viewmodel = new MockViewModel {
+ Text = "Foo"
+ };
+
+ var binding = new Binding ("Text");
+
+ var bindable = new MockBindable();
+ bindable.BindingContext = viewmodel;
+ bindable.SetBinding (MockBindable.TextProperty, binding);
+
+ string original = (string)bindable.GetValue (MockBindable.TextProperty);
+
+ bindable.RemoveBinding (MockBindable.TextProperty);
+
+ viewmodel.Text = newvalue;
+ Assert.AreEqual (original, bindable.GetValue (MockBindable.TextProperty),
+ "Property updated from a removed binding");
+ }
+
+ [Test]
+ public void CoerceValue()
+ {
+ var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, null,
+ coerceValue: (bo, o) => o.ToUpper());
+
+ const string value = "value";
+ var mock = new MockBindable();
+ mock.SetValue (property, value);
+ Assert.AreEqual (value.ToUpper(), mock.GetValue (property));
+ }
+
+ [Test]
+ public void ValidateValue()
+ {
+ var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, null,
+ validateValue: (b, v) => false);
+
+ var mock = new MockBindable();
+ Assert.Throws<ArgumentException> (() => mock.SetValue (property, null));
+ }
+
+ [Test]
+ public void BindablePropertyChanged()
+ {
+ bool changed = false;
+
+ string oldv = "bar";
+ string newv = "foo";
+
+ var property = BindableProperty.Create<MockBindable, string> (w => w.Foo, oldv,
+ propertyChanged: (b, ov, nv) => {
+ Assert.AreSame (oldv, ov);
+ Assert.AreSame (newv, nv);
+ changed = true;
+ });
+
+ var mock = new MockBindable();
+ mock.SetValue (property, newv);
+
+ Assert.IsTrue (changed, "PropertyChanged was not called");
+ }
+
+ [Test]
+ public void RecursiveChange ()
+ {
+ bool changedA1 = false, changedA2 = false, changedB1 = false, changedB2 = false;
+
+ var mock = new MockBindable ();
+ mock.PropertyChanged += (sender, args) => {
+ if (!changedA1) {
+ Assert.AreEqual ("1", mock.GetValue (MockBindable.TextProperty));
+ Assert.IsFalse (changedA2);
+ Assert.IsFalse (changedB1);
+ Assert.IsFalse (changedB2);
+ mock.SetValue (MockBindable.TextProperty, "2");
+ changedA1 = true;
+ } else {
+ Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty));
+ Assert.IsFalse (changedA2);
+ Assert.IsTrue (changedB1);
+ Assert.IsFalse (changedB2);
+ changedA2 = true;
+ }
+ };
+ mock.PropertyChanged += (sender, args) => {
+ if (!changedB1) {
+ Assert.AreEqual ("1", mock.GetValue (MockBindable.TextProperty));
+ Assert.IsTrue (changedA1);
+ Assert.IsFalse (changedA2);
+ Assert.IsFalse (changedB2);
+ changedB1 = true;
+ } else {
+ Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty));
+ Assert.IsTrue (changedA1);
+ Assert.IsTrue (changedA2);
+ Assert.IsFalse (changedB2);
+ changedB2 = true;
+ }
+ };
+ mock.SetValue (MockBindable.TextProperty, "1");
+ Assert.AreEqual ("2", mock.GetValue (MockBindable.TextProperty));
+ Assert.IsTrue (changedA1);
+ Assert.IsTrue (changedA2);
+ Assert.IsTrue (changedB1);
+ Assert.IsTrue (changedB2);
+ }
+
+ [Test]
+ public void RaiseOnEqual()
+ {
+ string foo = "foo";
+ var mock = new MockBindable();
+ mock.SetValue (MockBindable.TextProperty, foo);
+
+ bool changing = false;
+ mock.PropertyChanging += (o, e) => {
+ Assert.That (e.PropertyName, Is.EqualTo (MockBindable.TextProperty.PropertyName));
+ changing = true;
+ };
+
+ bool changed = true;
+ mock.PropertyChanged += (o, e) => {
+ Assert.That (e.PropertyName, Is.EqualTo (MockBindable.TextProperty.PropertyName));
+ changed = true;
+ };
+
+ mock.SetValueCore (MockBindable.TextProperty, foo,
+ BindableObject.SetValueFlags.ClearOneWayBindings | BindableObject.SetValueFlags.ClearDynamicResource | BindableObject.SetValueFlags.RaiseOnEqual);
+
+ Assert.That (changing, Is.True, "PropertyChanging event did not fire");
+ Assert.That (changed, Is.True, "PropertyChanged event did not fire");
+ }
+
+ [Test]
+ public void BindingContextGetter ()
+ {
+ var label = new Label ();
+ var view = new StackLayout { Children = {label} };
+
+ view.BindingContext = new {item0 = "Foo", item1 = "Bar"};
+ label.SetBinding (BindableObject.BindingContextProperty, "item0");
+ label.SetBinding (Label.TextProperty, Binding.SelfPath);
+
+ Assert.AreSame (label.BindingContext, label.GetValue (BindableObject.BindingContextProperty));
+ }
+
+ [Test]
+ public void BoundBindingContextUpdate ()
+ {
+ var label = new Label ();
+ var view = new StackLayout { Children = {label} };
+ var vm = new MockViewModel { Text = "FooBar" };
+
+ view.BindingContext = vm;
+ label.SetBinding (BindableObject.BindingContextProperty, "Text");
+ label.SetBinding (Label.TextProperty, Binding.SelfPath);
+
+ Assert.AreEqual ("FooBar", label.BindingContext);
+
+ vm.Text = "Baz";
+ Assert.AreEqual ("Baz", label.BindingContext);
+ }
+
+ [Test]
+ public void BoundBindingContextChange ()
+ {
+ var label = new Label ();
+ var view = new StackLayout { Children = {label} };
+
+ view.BindingContext = new MockViewModel { Text = "FooBar" };;
+ label.SetBinding (BindableObject.BindingContextProperty, "Text");
+ label.SetBinding (Label.TextProperty, Binding.SelfPath);
+
+ Assert.AreEqual ("FooBar", label.BindingContext);
+
+ view.BindingContext = new MockViewModel { Text = "Baz" };;
+ Assert.AreEqual ("Baz", label.BindingContext);
+ }
+
+ [Test]
+ public void TestReadOnly ()
+ {
+ var bindablePropertyKey = BindableProperty.CreateReadOnly<MockBindable, string> (w => w.Foo, "DefaultValue");
+ var bindableProperty = bindablePropertyKey.BindableProperty;
+
+ var bindable = new MockBindable ();
+ Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty));
+
+ bindable.SetValue (bindablePropertyKey, "Bar");
+ Assert.AreEqual ("Bar", bindable.GetValue (bindableProperty));
+
+ Assert.Throws<InvalidOperationException> (() => bindable.SetValue (bindableProperty, "Baz"));
+ Assert.AreEqual ("Bar", bindable.GetValue (bindableProperty));
+
+ Assert.Throws<InvalidOperationException> (() => bindable.ClearValue (bindableProperty));
+
+ bindable.ClearValue (bindablePropertyKey);
+ Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty));
+ }
+
+ [Test]
+ public void TestBindingTwoWayOnReadOnly ()
+ {
+ var bindablePropertyKey = BindableProperty.CreateReadOnly<MockBindable, string> (w => w.Foo, "DefaultValue", BindingMode.OneWayToSource);
+ var bindableProperty = bindablePropertyKey.BindableProperty;
+
+ var bindable = new MockBindable ();
+ var vm = new MockViewModel ();
+
+ bindable.SetBinding (bindableProperty, new Binding ("Text", BindingMode.TwoWay));
+ Assert.DoesNotThrow (() => bindable.BindingContext = vm);
+
+ Assert.AreEqual ("DefaultValue", bindable.GetValue (bindableProperty));
+ }
+
+ [Test]
+ public void DefaultValueCreator ()
+ {
+ int invoked = 0;
+ object defaultValue = new object ();
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), defaultValue, defaultValueCreator: o => {
+ invoked++;
+ return new object ();
+ });
+ var bindable = new MockBindable ();
+
+ Assert.AreSame (defaultValue, bindableProperty.DefaultValue);
+ var newvalue = bindable.GetValue (bindableProperty);
+ Assert.AreNotSame (defaultValue, newvalue);
+ Assert.NotNull (newvalue);
+ Assert.AreEqual (1, invoked);
+ }
+
+ [Test]
+ public void DefaultValueCreatorIsInvokedOnlyAtFirstTime ()
+ {
+ int invoked = 0;
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => {
+ invoked++;
+ return new object ();
+ });
+ var bindable = new MockBindable ();
+
+ var value0 = bindable.GetValue (bindableProperty);
+ var value1 = bindable.GetValue (bindableProperty);
+ Assert.NotNull (value0);
+ Assert.NotNull (value1);
+ Assert.AreSame (value0, value1);
+ Assert.AreEqual (1, invoked);
+ }
+
+ [Test]
+ public void DefaultValueCreatorNotSharedAccrossInstances ()
+ {
+ int invoked = 0;
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o=> {
+ invoked++;
+ return new object ();
+ });
+ var bindable0 = new MockBindable ();
+ var bindable1 = new MockBindable ();
+ var value0 = bindable0.GetValue (bindableProperty);
+ var value1 = bindable1.GetValue (bindableProperty);
+
+ Assert.AreNotSame (value0, value1);
+ Assert.AreEqual (2, invoked);
+ }
+
+ [Test]
+ public void DefaultValueCreatorInvokedAfterClearValue ()
+ {
+ int invoked = 0;
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => {
+ invoked++;
+ return new object ();
+ });
+ var bindable = new MockBindable ();
+
+ Assert.AreEqual (0, invoked);
+
+ var value0 = bindable.GetValue (bindableProperty);
+ Assert.NotNull (value0);
+ Assert.AreEqual (1, invoked);
+ bindable.ClearValue (bindableProperty);
+
+ var value1 = bindable.GetValue (bindableProperty);
+ Assert.NotNull (value1);
+ Assert.AreEqual (2, invoked);
+ Assert.AreNotSame (value0, value1);
+ }
+
+ [Test]
+ public void DefaultValueCreatorOnlyInvokedOnGetValue ()
+ {
+ int invoked = 0;
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null, defaultValueCreator: o => {
+ invoked++;
+ return new object ();
+ });
+ var bindable = new MockBindable ();
+
+ Assert.AreEqual (0, invoked);
+
+ var newvalue = bindable.GetValue (bindableProperty);
+ Assert.NotNull (newvalue);
+ Assert.AreEqual (1, invoked);
+ }
+
+ [Test]
+ public void DefaultValueCreatorDoesNotTriggerINPC ()
+ {
+ int invoked = 0;
+ int propertychanged = 0;
+ int changedfired = 0;
+ var bindableProperty = BindableProperty.Create ("Foo", typeof(object), typeof(MockBindable), null,
+ propertyChanged: (bindable,oldvalue,newvalue) =>{
+ propertychanged ++;
+ },
+ defaultValueCreator: o => {
+ invoked++;
+ return new object ();
+ });
+
+ var bp = new MockBindable ();
+ bp.PropertyChanged += (sender, e) => {
+ if (e.PropertyName == "Foo")
+ changedfired++;
+ };
+ var value0 = bp.GetValue (bindableProperty);
+ Assert.NotNull (value0);
+ Assert.AreEqual (1, invoked);
+ Assert.AreEqual (0, propertychanged);
+ Assert.AreEqual (0, changedfired);
+
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByValue ()
+ {
+ var label = new Label ();
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByValue ()
+ {
+ var label = new Label ();
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ label.BindingContext = new {foo = "Foo"};
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByValue ()
+ {
+ var label = new Label ();
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"}
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar");
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void ValueIsPreservedOnStyleValue ()
+ {
+ var label = new Label ();
+ label.SetValue (Label.TextProperty, "Foo");
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+ [Test]
+ public void BindingIsPreservedOnStyleValue ()
+ {
+ var label = new Label ();
+ label.SetBinding (Label.TextProperty, new Binding ("foo"));
+ label.BindingContext = new {foo = "Foo"};
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+ [Test]
+ public void DynResourceIsPreservedOnStyleValue ()
+ {
+ var label = new Label ();
+ label.SetDynamicResource (Label.TextProperty, "foo");
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"}
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void ValueIsPreservedOnStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo");
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding ("bar"), true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void BindingIsPreservedOnStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"));
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding ("bar"), true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void DynResourceIsPreservedOnStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo");
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding ("bar"), true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void ValueIsPreservedOnStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo");
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void BindingIsPreservedOnStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"));
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void DynResourceIsPreservedOnStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo");
+
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Foo", label.Text);
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByStyleValue ()
+ {
+ var label = new Label ();
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByStyleValue ()
+ {
+ var label = new Label ();
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ label.BindingContext = new {foo = "Foo"};
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByStyleValue ()
+ {
+ var label = new Label ();
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"}
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetValue (Label.TextProperty, "Bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding("bar"), true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding("bar"), true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByStyleBinding ()
+ {
+ var label = new Label ();
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ };
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetBinding (Label.TextProperty, new Binding("bar"), true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleValueIsOverridenByStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetValue (Label.TextProperty, "Foo", true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleBindingIsOverridenByStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetBinding (Label.TextProperty, new Binding ("foo"), true);
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void StyleDynResourceIsOverridenByStyleDynResource ()
+ {
+ var label = new Label ();
+ label.Resources = new ResourceDictionary {
+ {"foo", "Foo"},
+ {"bar", "Bar"}
+ };
+ label.BindingContext = new {foo = "Foo", bar = "Bar"};
+ label.SetDynamicResource (Label.TextProperty, "foo", true);
+
+ Assert.AreEqual ("Foo", label.Text);
+
+ label.SetDynamicResource (Label.TextProperty, "bar", true);
+ Assert.AreEqual ("Bar", label.Text);
+ }
+
+ [Test]
+ public void SetValueCoreImplicitelyCastBasicType ()
+ {
+ var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0);
+ var bindable = new MockBindable ();
+
+ Assert.DoesNotThrow (() => bindable.SetValue (prop, (object)(short)42));
+ Assert.AreEqual (42, bindable.GetValue (prop));
+
+ bindable.SetValue (prop, (object)(long)-42);
+ Assert.AreNotEqual (-42, bindable.GetValue (prop));
+ }
+
+ class CastFromString
+ {
+ public string Result { get; private set; }
+ public static implicit operator CastFromString (string source)
+ {
+ var o = new CastFromString ();
+ o.Result = source;
+ return o;
+ }
+ }
+
+ [Test]
+ public void SetValueCoreInvokesOpImplicitOnPropertyType ()
+ {
+ var prop = BindableProperty.Create ("Foo", typeof(CastFromString), typeof(MockBindable), null);
+ var bindable = new MockBindable ();
+
+ Assert.Null (bindable.GetValue (prop));
+ bindable.SetValue (prop, "foo");
+
+ Assert.AreEqual ("foo", ((CastFromString)bindable.GetValue (prop)).Result);
+ }
+
+ class CastToString
+ {
+ string Result { get; set; }
+
+ public CastToString (string result)
+ {
+ Result = result;
+ }
+
+ public static implicit operator string (CastToString source)
+ {
+ return source.Result;
+ }
+
+ public override string ToString ()
+ {
+ throw new InvalidOperationException ();
+ }
+ }
+
+ [Test]
+ public void SetValueCoreInvokesOpImplicitOnValue ()
+ {
+ var prop = BindableProperty.Create ("Foo", typeof(string), typeof(MockBindable), null);
+ var bindable = new MockBindable ();
+
+ Assert.Null (bindable.GetValue (prop));
+ bindable.SetValue (prop, new CastToString ("foo"));
+
+ Assert.AreEqual ("foo", bindable.GetValue (prop));
+ }
+
+ [Test]
+ public void DefaultValueCreatorCalledForChangeDelegates ()
+ {
+ int changedOld = -1;
+ int changedNew = -1;
+
+ int changingOld = -1;
+ int changingNew = -1;
+ var prop = BindableProperty.Create ("Foo", typeof (int), typeof (MockBindable), 0, defaultValueCreator: b => 10,
+ propertyChanged: (b, value, newValue) => {
+ changedOld = (int) value;
+ changedNew = (int) newValue;
+ },
+ propertyChanging: (b, value, newValue) => {
+ changingOld = (int) value;
+ changingNew = (int) newValue;
+ });
+
+ var bindable = new MockBindable ();
+
+
+ var defaultValue = (int) bindable.GetValue (prop);
+
+ Assert.AreEqual (10, defaultValue);
+
+ bindable.SetValue (prop, 5);
+
+ bindable.ClearValue (prop);
+
+ Assert.AreEqual (5, changedOld);
+ Assert.AreEqual (5, changingOld);
+ Assert.AreEqual (10, changedNew);
+ Assert.AreEqual (10, changingNew);
+ }
+
+ [Test]
+ public void GetValuesDefaults()
+ {
+ var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0);
+ var prop1 = BindableProperty.Create ("Foo1", typeof(int), typeof(MockBindable), 1);
+ var prop2 = BindableProperty.Create ("Foo2", typeof(int), typeof(MockBindable), 2);
+ var bindable = new MockBindable ();
+
+
+ object[] values = bindable.GetValues (prop, prop1, prop2);
+ Assert.That (values.Length == 3);
+ Assert.That (values[0], Is.EqualTo (0));
+ Assert.That (values[1], Is.EqualTo (1));
+ Assert.That (values[2], Is.EqualTo (2));
+ }
+
+ [Test]
+ public void GetValues()
+ {
+ var prop = BindableProperty.Create ("Foo", typeof(int), typeof(MockBindable), 0);
+ var prop1 = BindableProperty.Create ("Foo1", typeof(int), typeof(MockBindable), 1);
+ var prop2 = BindableProperty.Create ("Foo2", typeof(int), typeof(MockBindable), 2);
+ var bindable = new MockBindable ();
+ bindable.SetValue (prop, 3);
+ bindable.SetValue (prop2, 5);
+
+
+ object[] values = bindable.GetValues (prop, prop1, prop2);
+ Assert.That (values.Length == 3);
+ Assert.That (values[0], Is.EqualTo (3));
+ Assert.That (values[1], Is.EqualTo (1));
+ Assert.That (values[2], Is.EqualTo (5));
+ }
+
+ class BindingContextConverter
+ : IValueConverter
+ {
+ public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return new MockViewModel { Text = value + "Converted" };
+ }
+
+ public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [Test]
+ //https://bugzilla.xamarin.com/show_bug.cgi?id=24485
+ public void BindingContextBoundThroughConverter()
+ {
+ var bindable = new MockBindable();
+ bindable.BindingContext = "test";
+ bindable.SetBinding (BindableObject.BindingContextProperty, new Binding (".", converter: new BindingContextConverter()));
+ bindable.SetBinding (MockBindable.TextProperty, "Text");
+
+ Assert.That (() => bindable.Text, Is.EqualTo ("testConverted"));
+ }
+
+ public class VMLocator
+ {
+ public event EventHandler Invoked;
+ public int Count;
+ public object VM {
+ get {
+ Count++;
+ var eh = Invoked;
+ if (eh != null)
+ eh (this, EventArgs.Empty);
+ return new object ();
+ }
+ }
+ }
+
+ [Test]
+ //https://bugzilla.xamarin.com/show_bug.cgi?id=27299
+ public void BindingOnBindingContextDoesntReapplyBindingContextBinding ()
+ {
+ var bindable = new MockBindable ();
+ var locator = new VMLocator ();
+ Assert.AreEqual (0, locator.Count);
+ locator.Invoked += (sender, e) => Assert.IsTrue (locator.Count <= 1);
+ bindable.SetBinding (BindableObject.BindingContextProperty, new Binding ("VM", source: locator));
+ Assert.IsTrue (locator.Count == 1);
+ }
+
+ [Test]
+ public void BindingsEditableAfterUnapplied()
+ {
+ var bindable = new MockBindable();
+
+ var binding = new Binding (".");
+ bindable.SetBinding (MockBindable.TextProperty, binding);
+ bindable.BindingContext = "foo";
+
+ Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext));
+
+ bindable.RemoveBinding (MockBindable.TextProperty);
+
+ Assert.That (() => binding.Path = "foo", Throws.Nothing);
+ }
+
+ [Test]
+ // https://bugzilla.xamarin.com/show_bug.cgi?id=24054
+ public void BindingsAppliedUnappliedWithNullContext()
+ {
+ var bindable = new MockBindable();
+
+ var binding = new Binding (".");
+ bindable.SetBinding (MockBindable.TextProperty, binding);
+ bindable.BindingContext = "foo";
+
+ Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext));
+
+ bindable.BindingContext = null;
+
+ Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext));
+
+ bindable.BindingContext = "bar";
+
+ Assume.That (bindable.Text, Is.EqualTo (bindable.BindingContext));
+
+ bindable.RemoveBinding (MockBindable.TextProperty);
+
+ Assert.That (() => binding.Path = "Foo", Throws.Nothing);
+ }
+ }
+} \ No newline at end of file