summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core
diff options
context:
space:
mode:
authorStephane Delcroix <stephane@delcroix.org>2017-04-28 21:11:38 +0200
committerStephane Delcroix <stephane@delcroix.org>2017-05-03 10:03:37 +0200
commitbe49aed1c74285531206a8ce2467bec18e3a92b0 (patch)
treefe8e3a8b0b90cec19ff3c7b750636c353e35c5a0 /Xamarin.Forms.Core
parentdc3c410c5df3b62d9eb312e60ea25b1de61fe2c5 (diff)
downloadxamarin-forms-be49aed1c74285531206a8ce2467bec18e3a92b0.tar.gz
xamarin-forms-be49aed1c74285531206a8ce2467bec18e3a92b0.tar.bz2
xamarin-forms-be49aed1c74285531206a8ce2467bec18e3a92b0.zip
[Xaml] move ValueConverterProvider to Core (#890)
* [Xaml] move ValueConverterProvider to Core * [docs] fix docs
Diffstat (limited to 'Xamarin.Forms.Core')
-rw-r--r--Xamarin.Forms.Core/Xamarin.Forms.Core.csproj5
-rw-r--r--Xamarin.Forms.Core/Xaml/TypeConversionExtensions.cs216
-rw-r--r--Xamarin.Forms.Core/Xaml/ValueConverterProvider.cs17
3 files changed, 238 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
index 1184e012..385ab4c7 100644
--- a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
+++ b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
@@ -460,6 +460,8 @@
<Compile Include="ITextElement.cs" />
<Compile Include="TextElement.cs" />
<Compile Include="Internals\ResourceLoader.cs" />
+ <Compile Include="Xaml\TypeConversionExtensions.cs" />
+ <Compile Include="Xaml\ValueConverterProvider.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup>
@@ -475,4 +477,7 @@
</PropertyGroup>
<ItemGroup />
<ItemGroup />
+ <ItemGroup>
+ <Folder Include="Xaml\" />
+ </ItemGroup>
</Project>
diff --git a/Xamarin.Forms.Core/Xaml/TypeConversionExtensions.cs b/Xamarin.Forms.Core/Xaml/TypeConversionExtensions.cs
new file mode 100644
index 00000000..09df9a24
--- /dev/null
+++ b/Xamarin.Forms.Core/Xaml/TypeConversionExtensions.cs
@@ -0,0 +1,216 @@
+//
+// TypeConversionExtensions.cs
+//
+// Author:
+// Stephane Delcroix <stephane@mi8.be>
+//
+// Copyright (c) 2013 Mobile Inception
+// Copyright (c) 2014 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Xaml.Internals;
+
+namespace Xamarin.Forms.Xaml
+{
+ static class TypeConversionExtensions
+ {
+ internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
+ IServiceProvider serviceProvider)
+ {
+ Func<TypeConverter> getConverter = () =>
+ {
+ ParameterInfo pInfo;
+ if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
+ return null;
+
+ var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
+ if (converterTypeName == null)
+ return null;
+ var convertertype = Type.GetType(converterTypeName);
+ return (TypeConverter)Activator.CreateInstance(convertertype);
+ };
+
+ return ConvertTo(value, toType, getConverter, serviceProvider);
+ }
+
+ internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
+ IServiceProvider serviceProvider)
+ {
+ Func<object> getConverter = () =>
+ {
+ MemberInfo memberInfo;
+
+ var converterTypeName = toType.GetTypeInfo().CustomAttributes.GetTypeConverterTypeName();
+ if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
+ converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
+ if (converterTypeName == null)
+ return null;
+
+ var convertertype = Type.GetType(converterTypeName);
+ return Activator.CreateInstance(convertertype);
+ };
+
+ return ConvertTo(value, toType, getConverter, serviceProvider);
+ }
+
+ static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
+ {
+ var converterAttribute =
+ attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
+ if (converterAttribute == null)
+ return null;
+ if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (string))
+ return (string)converterAttribute.ConstructorArguments[0].Value;
+ if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (Type))
+ return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
+ return null;
+ }
+
+ //Don't change the name or the signature of this, it's used by XamlC
+ public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
+ {
+ if (convertertype == null)
+ return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
+ Func<object> getConverter = () => Activator.CreateInstance(convertertype);
+ ;
+ return value.ConvertTo(toType, getConverter, serviceProvider);
+ }
+
+ internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
+ IServiceProvider serviceProvider)
+ {
+ if (value == null)
+ return null;
+
+ var str = value as string;
+ if (str != null)
+ {
+ //If there's a [TypeConverter], use it
+ object converter = getConverter?.Invoke();
+ var xfTypeConverter = converter as TypeConverter;
+ var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
+ if (xfExtendedTypeConverter != null)
+ return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
+ if (xfTypeConverter != null)
+ return value = xfTypeConverter.ConvertFromInvariantString(str);
+ var converterType = converter?.GetType();
+ if (converterType != null)
+ {
+ var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
+ new[] { typeof (string) });
+ if (convertFromStringInvariant != null)
+ return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
+ }
+
+ //If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
+ if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof (Nullable<>))
+ toType = Nullable.GetUnderlyingType(toType);
+
+ //Obvious Built-in conversions
+ if (toType.GetTypeInfo().IsEnum)
+ return Enum.Parse(toType, str);
+ if (toType == typeof(SByte))
+ return SByte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int16))
+ return Int16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int32))
+ return Int32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int64))
+ return Int64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Byte))
+ return Byte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt16))
+ return UInt16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt32))
+ return UInt32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt64))
+ return UInt64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Single))
+ return Single.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Double))
+ return Double.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Boolean))
+ return Boolean.Parse(str);
+ if (toType == typeof (TimeSpan))
+ return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (DateTime))
+ return DateTime.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Char)) {
+ char c = '\0';
+ Char.TryParse(str, out c);
+ return c;
+ }
+ if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
+ return str.Substring(2);
+ if (toType == typeof (String))
+ return value;
+ if (toType == typeof(Decimal))
+ return Decimal.Parse(str, CultureInfo.InvariantCulture);
+ }
+
+ //if there's an implicit conversion, convert
+ if (value != null) {
+ MethodInfo opImplicit = null;
+ foreach (var mi in value.GetType().GetRuntimeMethods()) {
+ if (!mi.IsSpecialName) continue;
+ if (mi.Name != "op_Implicit") continue;
+ if (!mi.IsPublic) continue;
+ if (!toType.IsAssignableFrom(mi.ReturnType)) continue;
+ var parameters = mi.GetParameters();
+ if (parameters.Length != 1) continue;
+ if (parameters[0].ParameterType != value.GetType()) continue;
+ opImplicit = mi;
+ break;
+ }
+ if (opImplicit == null) {
+ foreach (var mi in toType.GetRuntimeMethods()) {
+ if (!mi.IsSpecialName) continue;
+ if (mi.Name != "op_Implicit") continue;
+ if (!mi.IsPublic) continue;
+ if (!toType.IsAssignableFrom(mi.ReturnType)) continue;
+ var parameters = mi.GetParameters();
+ if (parameters.Length != 1) continue;
+ if (parameters[0].ParameterType != value.GetType()) continue;
+ opImplicit = mi;
+ break;
+ }
+ }
+ if (opImplicit != null) {
+ value = opImplicit.Invoke(null, new[] { value });
+ return value;
+ }
+ }
+
+ var nativeValueConverterService = DependencyService.Get<INativeValueConverterService>();
+
+ object nativeValue = null;
+ if (nativeValueConverterService != null && nativeValueConverterService.ConvertTo(value, toType, out nativeValue))
+ return nativeValue;
+
+ return value;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Core/Xaml/ValueConverterProvider.cs b/Xamarin.Forms.Core/Xaml/ValueConverterProvider.cs
new file mode 100644
index 00000000..ef5edc98
--- /dev/null
+++ b/Xamarin.Forms.Core/Xaml/ValueConverterProvider.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Reflection;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+[assembly:Dependency(typeof(ValueConverterProvider))]
+namespace Xamarin.Forms.Xaml
+{
+ class ValueConverterProvider : IValueConverterProvider
+ {
+ public object Convert(object value, Type toType, Func<MemberInfo> minfoRetriever, IServiceProvider serviceProvider)
+ {
+ return value.ConvertTo(toType, minfoRetriever, serviceProvider);
+ }
+ }
+}