315 строки
7.4 KiB
C#
315 строки
7.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using NUnit.Framework;
|
|
|
|
namespace Xamarin.Forms.Core.UnitTests
|
|
{
|
|
[TestFixture]
|
|
public class DynamicBindingContextTests
|
|
{
|
|
[Test]
|
|
public void BindingTwoWayToDynamicModel()
|
|
{
|
|
var view = new MockBindable();
|
|
var model = new DynamicModel
|
|
{
|
|
Properties =
|
|
{
|
|
{ "Title", "Foo" },
|
|
}
|
|
};
|
|
|
|
view.SetBinding(MockBindable.TextProperty, "Title");
|
|
view.BindingContext = model;
|
|
|
|
Assert.AreEqual("Foo", view.Text);
|
|
|
|
view.Text = "Bar";
|
|
|
|
Assert.AreEqual("Bar", model.Properties["Title"]);
|
|
}
|
|
|
|
// This whole class and inner types is just a very simple
|
|
// dictionary-based dynamic model that proves that the
|
|
// approach works. It implements just the bare minimum of
|
|
// the base types to get our bindings to work properly and
|
|
// pass the tests.
|
|
class DynamicModel : IReflectableType
|
|
{
|
|
public DynamicModel()
|
|
{
|
|
Properties = new Dictionary<string, object>();
|
|
}
|
|
|
|
public TypeInfo GetTypeInfo()
|
|
{
|
|
return new DynamicTypeInfo(Properties);
|
|
}
|
|
|
|
public IDictionary<string, object> Properties { get; private set; }
|
|
|
|
class DynamicTypeInfo : TypeDelegator
|
|
{
|
|
IDictionary<string, object> properties;
|
|
|
|
public DynamicTypeInfo(IDictionary<string, object> properties)
|
|
: base(typeof(object))
|
|
{
|
|
this.properties = properties;
|
|
}
|
|
|
|
public override PropertyInfo GetDeclaredProperty(string name)
|
|
{
|
|
if (!properties.ContainsKey(name))
|
|
return null;
|
|
|
|
return new DynamicPropertyInfo(properties, name);
|
|
}
|
|
|
|
internal class DynamicPropertyInfo : PropertyInfo
|
|
{
|
|
IDictionary<string, object> properties;
|
|
string name;
|
|
|
|
public DynamicPropertyInfo(IDictionary<string, object> properties, string name)
|
|
{
|
|
this.properties = properties;
|
|
this.name = name;
|
|
}
|
|
|
|
public override bool CanRead
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public override bool CanWrite
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public override MethodInfo GetGetMethod(bool nonPublic)
|
|
{
|
|
return new DynamicPropertyGetterInfo(this, properties);
|
|
}
|
|
|
|
public override MethodInfo GetSetMethod(bool nonPublic)
|
|
{
|
|
return new DynamicPropertySetterInfo(this, properties);
|
|
}
|
|
|
|
public override Type PropertyType
|
|
{
|
|
get { return properties[name].GetType(); }
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return name; }
|
|
}
|
|
|
|
public override PropertyAttributes Attributes
|
|
{
|
|
get { return PropertyAttributes.None; }
|
|
}
|
|
|
|
public override MethodInfo[] GetAccessors(bool nonPublic)
|
|
{
|
|
return new[] { GetGetMethod(nonPublic), GetSetMethod(nonPublic) };
|
|
}
|
|
|
|
public override ParameterInfo[] GetIndexParameters()
|
|
{
|
|
return new ParameterInfo[0];
|
|
}
|
|
|
|
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override Type DeclaringType
|
|
{
|
|
get { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override object[] GetCustomAttributes(bool inherit)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override bool IsDefined(Type attributeType, bool inherit)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override Type ReflectedType
|
|
{
|
|
get { throw new NotImplementedException(); }
|
|
}
|
|
}
|
|
|
|
internal class DynamicPropertyGetterInfo : DynamicPropertyMethodInfo
|
|
{
|
|
public DynamicPropertyGetterInfo(PropertyInfo property, IDictionary<string, object> properties)
|
|
: base(property, properties)
|
|
{
|
|
}
|
|
|
|
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
|
|
{
|
|
return Properties[Property.Name];
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters()
|
|
{
|
|
return new[] { new DynamicParameterInfo(Property, Property.PropertyType, "value") };
|
|
}
|
|
|
|
public override Type ReturnType
|
|
{
|
|
get { return Property.PropertyType; }
|
|
}
|
|
}
|
|
|
|
internal class DynamicPropertySetterInfo : DynamicPropertyMethodInfo
|
|
{
|
|
public DynamicPropertySetterInfo(PropertyInfo property, IDictionary<string, object> properties)
|
|
: base(property, properties)
|
|
{
|
|
}
|
|
|
|
public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
|
|
{
|
|
Properties[Property.Name] = parameters[0];
|
|
return null;
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters()
|
|
{
|
|
return new[] {
|
|
new DynamicParameterInfo (Property, typeof(DynamicTypeInfo), "this"),
|
|
new DynamicParameterInfo (Property, Property.PropertyType, "value")
|
|
};
|
|
}
|
|
|
|
public override Type ReturnType
|
|
{
|
|
get { return typeof(void); }
|
|
}
|
|
}
|
|
|
|
internal abstract class DynamicPropertyMethodInfo : MethodInfo
|
|
{
|
|
public DynamicPropertyMethodInfo(PropertyInfo property, IDictionary<string, object> properties)
|
|
{
|
|
Property = property;
|
|
Properties = properties;
|
|
}
|
|
|
|
protected PropertyInfo Property { get; private set; }
|
|
|
|
protected IDictionary<string, object> Properties { get; private set; }
|
|
|
|
public override MethodInfo GetBaseDefinition()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override ICustomAttributeProvider ReturnTypeCustomAttributes
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
public override MethodAttributes Attributes
|
|
{
|
|
get { return MethodAttributes.Public; }
|
|
}
|
|
|
|
public override MethodImplAttributes GetMethodImplementationFlags()
|
|
{
|
|
return MethodImplAttributes.IL;
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters()
|
|
{
|
|
return new ParameterInfo[0];
|
|
}
|
|
|
|
public override RuntimeMethodHandle MethodHandle
|
|
{
|
|
get { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public override Type DeclaringType
|
|
{
|
|
get { return typeof(DynamicModel); }
|
|
}
|
|
|
|
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
|
{
|
|
return new object[0];
|
|
}
|
|
|
|
public override object[] GetCustomAttributes(bool inherit)
|
|
{
|
|
return new object[0];
|
|
}
|
|
|
|
public override bool IsDefined(Type attributeType, bool inherit)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return Property.Name; }
|
|
}
|
|
|
|
public override Type ReflectedType
|
|
{
|
|
get { return typeof(DynamicModel); }
|
|
}
|
|
}
|
|
|
|
internal class DynamicParameterInfo : ParameterInfo
|
|
{
|
|
MemberInfo member;
|
|
Type type;
|
|
|
|
public DynamicParameterInfo(MemberInfo member, Type type, string name)
|
|
{
|
|
this.member = member;
|
|
this.type = type;
|
|
}
|
|
|
|
public override MemberInfo Member
|
|
{
|
|
get { return member; }
|
|
}
|
|
|
|
public override Type ParameterType
|
|
{
|
|
get { return type; }
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|