maui-linux/Xamarin.Forms.Core.UnitTests/BindableObjectUnitTests.cs

1411 строки
40 KiB
C#

using System;
using System.Globalization;
using NUnit.Framework;
using Xamarin.Forms.Internals;
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]
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()
{
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,
SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource | 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);
}
}
}