diff --git a/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs b/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs index e9b8de3..7c73312 100644 --- a/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs +++ b/Xamarin.PropertyEditing.Tests/MockEditorProvider.cs @@ -20,6 +20,11 @@ namespace Xamarin.PropertyEditing.Tests return Task.FromResult (editor); } + public Task CreateObjectAsync (ITypeInfo type) + { + throw new System.NotImplementedException (); + } + private Dictionary editorCache = new Dictionary (); } } \ No newline at end of file diff --git a/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs b/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs index 714f527..5381568 100644 --- a/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs +++ b/Xamarin.PropertyEditing.Tests/MockObjectEditor.cs @@ -106,6 +106,11 @@ namespace Xamarin.PropertyEditing.Tests return Task.FromResult> (new string[0]); } + public Task> GetAssignableTypesAsync (IPropertyInfo property) + { + throw new NotImplementedException(); + } + #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously public async Task SetValueAsync (IPropertyInfo property, ValueInfo value, PropertyVariation variation = null) { diff --git a/Xamarin.PropertyEditing/IAssemblyInfo.cs b/Xamarin.PropertyEditing/IAssemblyInfo.cs new file mode 100644 index 0000000..c693879 --- /dev/null +++ b/Xamarin.PropertyEditing/IAssemblyInfo.cs @@ -0,0 +1,63 @@ +using System; + +namespace Xamarin.PropertyEditing +{ + public interface IAssemblyInfo + { + string Name { get; } + } + + public class AssemblyInfo + : IAssemblyInfo, IEquatable + { + public AssemblyInfo (string name) + { + if (name == null) + throw new ArgumentNullException (nameof(name)); + + Name = name; + } + + public string Name + { + get; + } + + public bool Equals (AssemblyInfo other) + { + if (ReferenceEquals (null, other)) + return false; + if (ReferenceEquals (this, other)) + return true; + + return string.Equals (Name, other.Name); + } + + public override bool Equals (object obj) + { + if (ReferenceEquals (null, obj)) + return false; + if (ReferenceEquals (this, obj)) + return true; + if (obj.GetType () != GetType ()) + return false; + + return Equals ((AssemblyInfo) obj); + } + + public override int GetHashCode () + { + return Name.GetHashCode (); + } + + public static bool operator == (AssemblyInfo left, AssemblyInfo right) + { + return Equals (left, right); + } + + public static bool operator != (AssemblyInfo left, AssemblyInfo right) + { + return !Equals (left, right); + } + } +} diff --git a/Xamarin.PropertyEditing/IEditorProvider.cs b/Xamarin.PropertyEditing/IEditorProvider.cs index 48f572a..6336449 100644 --- a/Xamarin.PropertyEditing/IEditorProvider.cs +++ b/Xamarin.PropertyEditing/IEditorProvider.cs @@ -1,9 +1,14 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Xamarin.PropertyEditing { public interface IEditorProvider { Task GetObjectEditorAsync (object item); + + /// + /// Creates a representation value of the and returns it. + /// + Task CreateObjectAsync (ITypeInfo type); } } \ No newline at end of file diff --git a/Xamarin.PropertyEditing/IObjectEditor.cs b/Xamarin.PropertyEditing/IObjectEditor.cs index 18148b3..7fb630a 100644 --- a/Xamarin.PropertyEditing/IObjectEditor.cs +++ b/Xamarin.PropertyEditing/IObjectEditor.cs @@ -58,6 +58,8 @@ namespace Xamarin.PropertyEditing /// event EventHandler PropertyChanged; + Task> GetAssignableTypesAsync (IPropertyInfo property); + /* * Dealing with async values in the context of what's possible across all target platforms is a bit complex. * While implicit safety may be able to be ensured, it would be exhaustive to reason it out and could change diff --git a/Xamarin.PropertyEditing/ITypeInfo.cs b/Xamarin.PropertyEditing/ITypeInfo.cs new file mode 100644 index 0000000..baec4ef --- /dev/null +++ b/Xamarin.PropertyEditing/ITypeInfo.cs @@ -0,0 +1,86 @@ +using System; + +namespace Xamarin.PropertyEditing +{ + public interface ITypeInfo + { + IAssemblyInfo Assembly { get; } + string NameSpace { get; } + string Name { get; } + } + + public class TypeInfo + : ITypeInfo, IEquatable + { + public TypeInfo (IAssemblyInfo assembly, string nameSpace, string name) + { + if (assembly == null) + throw new ArgumentNullException (nameof(assembly)); + if (nameSpace == null) + throw new ArgumentNullException (nameof(nameSpace)); + if (name == null) + throw new ArgumentNullException (nameof(name)); + + Assembly = assembly; + NameSpace = nameSpace; + Name = name; + } + + public IAssemblyInfo Assembly + { + get; + } + + public string NameSpace + { + get; + } + + public string Name + { + get; + } + + public bool Equals (TypeInfo other) + { + if (ReferenceEquals (null, other)) + return false; + if (ReferenceEquals (this, other)) + return true; + + return Assembly.Equals (other.Assembly) && String.Equals (NameSpace, other.NameSpace) && String.Equals (Name, other.Name); + } + + public override bool Equals (object obj) + { + if (ReferenceEquals (null, obj)) + return false; + if (ReferenceEquals (this, obj)) + return true; + if (obj.GetType () != GetType ()) + return false; + + return Equals ((TypeInfo) obj); + } + + public override int GetHashCode () + { + unchecked { + var hashCode = Assembly.GetHashCode (); + hashCode = (hashCode * 397) ^ NameSpace.GetHashCode (); + hashCode = (hashCode * 397) ^ Name.GetHashCode (); + return hashCode; + } + } + + public static bool operator == (TypeInfo left, TypeInfo right) + { + return Equals (left, right); + } + + public static bool operator != (TypeInfo left, TypeInfo right) + { + return !Equals (left, right); + } + } +} diff --git a/Xamarin.PropertyEditing/Reflection/ReflectionEditorProvider.cs b/Xamarin.PropertyEditing/Reflection/ReflectionEditorProvider.cs index 9826f3d..1cdced2 100644 --- a/Xamarin.PropertyEditing/Reflection/ReflectionEditorProvider.cs +++ b/Xamarin.PropertyEditing/Reflection/ReflectionEditorProvider.cs @@ -10,5 +10,20 @@ namespace Xamarin.PropertyEditing.Reflection { return Task.FromResult (new ReflectionObjectEditor (item)); } + + public Task CreateObjectAsync (ITypeInfo type) + { + var realType = GetRealType (type); + if (realType == null) + return Task.FromResult (null); + + object instance = Activator.CreateInstance (realType); + return Task.FromResult (instance); + } + + public static Type GetRealType (ITypeInfo type) + { + return Type.GetType ($"{type.NameSpace}.{type.Name}, {type.Assembly.Name}"); + } } } \ No newline at end of file diff --git a/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs b/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs index 3cfb70b..17272cc 100644 --- a/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs +++ b/Xamarin.PropertyEditing/Reflection/ReflectionObjectEditor.cs @@ -92,6 +92,21 @@ namespace Xamarin.PropertyEditing.Reflection return Task.FromResult (info.GetHandlers (this.target)); } + public Task> GetAssignableTypesAsync (IPropertyInfo property) + { + return Task.Run (() => { + ReflectionPropertyInfo realInfo = (ReflectionPropertyInfo) property; + var assemblies = AppDomain.CurrentDomain.GetAssemblies (); + + return (IReadOnlyList)assemblies.Select (a => new { Assembly = a, Info = new AssemblyInfo (a.FullName)}) + .SelectMany (a => + a.Assembly.DefinedTypes.Select (t => new { Type = t, Assembly = a })) + .AsParallel () + .Where (t => realInfo.Type.IsAssignableFrom (t.Type)) + .Select (t => new TypeInfo (t.Assembly.Info, t.Type.Namespace, t.Type.Name)).ToList(); + }); + } + public async Task SetValueAsync (IPropertyInfo property, ValueInfo value, PropertyVariation variation = null) { if (property == null) diff --git a/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj b/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj index e487c8a..f41d6dd 100644 --- a/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj +++ b/Xamarin.PropertyEditing/Xamarin.PropertyEditing.csproj @@ -63,6 +63,7 @@ + @@ -75,6 +76,7 @@ +