Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[CSS] accept CSS values in converters
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneDelcroix committed Nov 28, 2017
1 parent a72549a commit cb35e96
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 20 deletions.
3 changes: 2 additions & 1 deletion Xamarin.Forms.Core/FontSizeConverter.cs
Expand Up @@ -20,8 +20,9 @@ object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceP
double size;
if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out size))
return size;
var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
NamedSize namedSize;
if (Enum.TryParse(value, out namedSize))
if (Enum.TryParse(value, ignoreCase, out namedSize))
{
Type type;
var valueTargetProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
Expand Down
7 changes: 7 additions & 0 deletions Xamarin.Forms.Core/IConverterOptions.cs
@@ -0,0 +1,7 @@
namespace Xamarin.Forms.Xaml
{
public interface IConverterOptions
{
bool IgnoreCase { get; }
}
}
7 changes: 4 additions & 3 deletions Xamarin.Forms.Core/StyleSheets/Style.cs
Expand Up @@ -69,7 +69,7 @@ public void Apply(VisualElement styleable)
else {
object value;
if (!convertedValues.TryGetValue(decl, out value))
convertedValues[decl] = (value = Convert(decl.Value, property));
convertedValues[decl] = (value = Convert(styleable, decl.Value, property));
styleable.SetValue(property, value, fromStyle: true);
}
}
Expand All @@ -83,11 +83,12 @@ public void Apply(VisualElement styleable)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static object Convert(object value, BindableProperty property)
static object Convert(object target, object value, BindableProperty property)
{
Func<MemberInfo> minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName) as MemberInfo
?? property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new[] { typeof(BindableObject) }) as MemberInfo;
return value.ConvertTo(property.ReturnType, minforetriever, null);
var serviceProvider = new StyleSheetServiceProvider(target, property);
return value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
}

public void UnApply(IStylable styleable)
Expand Down
39 changes: 39 additions & 0 deletions Xamarin.Forms.Core/StyleSheets/StyleSheetServiceProvider.cs
@@ -0,0 +1,39 @@
using System;
using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.StyleSheets
{
class StyleSheetServiceProvider : IServiceProvider
{
IProvideValueTarget vtProvider;
IConverterOptions convOptions => new ConverterOptions();

public StyleSheetServiceProvider(object targetObject, object targetProperty)
{
vtProvider = new ValueTargetProvider {
TargetObject = targetObject,
TargetProperty = targetProperty
};
}

public object GetService(Type serviceType)
{
if (serviceType == typeof(IProvideValueTarget))
return vtProvider;
if (serviceType == typeof(IConverterOptions))
return convOptions;
return null;
}

class ValueTargetProvider : IProvideValueTarget
{
public object TargetObject { get; set; }
public object TargetProperty { get; set; }
}

class ConverterOptions : IConverterOptions
{
public bool IgnoreCase => true;
}
}
}
31 changes: 16 additions & 15 deletions Xamarin.Forms.Core/ThicknessTypeConverter.cs
Expand Up @@ -13,21 +13,22 @@ public override object ConvertFromInvariantString(string value)
{
double l, t, r, b;
string[] thickness = value.Split(',');
switch (thickness.Length)
{
case 1:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l))
return new Thickness(l);
break;
case 2:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t))
return new Thickness(l, t);
break;
case 4:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t) &&
double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out r) && double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out b))
return new Thickness(l, t, r, b);
break;
if (thickness.Length == 1 && thickness[0].Trim().Contains(" "))
thickness = value.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
switch (thickness.Length) {
case 1:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l))
return new Thickness(l);
break;
case 2:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t))
return new Thickness(l, t);
break;
case 4:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t) &&
double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out r) && double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out b))
return new Thickness(l, t, r, b);
break;
}
}

Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
Expand Up @@ -492,6 +492,8 @@
<Compile Include="IBorderElement.cs" />
<Compile Include="BorderElement.cs" />
<Compile Include="StyleSheets\StyleSheetExtensions.cs" />
<Compile Include="StyleSheets\StyleSheetServiceProvider.cs" />
<Compile Include="IConverterOptions.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion Xamarin.Forms.Core/Xaml/TypeConversionExtensions.cs
Expand Up @@ -124,14 +124,15 @@ public static object ConvertTo(this object value, Type toType, Type convertertyp
if (convertFromStringInvariant != null)
return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
}
var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;

//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);
return Enum.Parse(toType, str, ignoreCase);
if (toType == typeof(SByte))
return SByte.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof(Int16))
Expand Down

0 comments on commit cb35e96

Please sign in to comment.