diff --git a/src/Perspex.Base/Utilities/TypeUtilities.cs b/src/Perspex.Base/Utilities/TypeUtilities.cs
index a8a5ec4d18..3d19de5f97 100644
--- a/src/Perspex.Base/Utilities/TypeUtilities.cs
+++ b/src/Perspex.Base/Utilities/TypeUtilities.cs
@@ -74,9 +74,8 @@ namespace Perspex.Utilities
}
else
{
- var cast = from.GetTypeInfo()
- .GetDeclaredMethods("op_Implicit")
- .FirstOrDefault(m => m.ReturnType == to);
+ var cast = from.GetRuntimeMethods()
+ .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to);
if (cast != null)
{
@@ -100,9 +99,27 @@ namespace Perspex.Utilities
/// True if the cast was sucessful, otherwise false.
public static bool TryConvert(Type to, object value, CultureInfo culture, out object result)
{
- var valueType = value.GetType();
+ if (value == null)
+ {
+ result = null;
+ return AcceptsNull(to);
+ }
+
+ var from = value.GetType();
+
+ if (value == PerspexProperty.UnsetValue)
+ {
+ result = value;
+ return true;
+ }
- if (to.GetTypeInfo().IsEnum && valueType == typeof(string))
+ if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
+ {
+ result = value;
+ return true;
+ }
+
+ if (to.GetTypeInfo().IsEnum && from == typeof(string))
{
if (Enum.IsDefined(to, (string)value))
{
@@ -111,8 +128,12 @@ namespace Perspex.Utilities
}
}
- if ((valueType == typeof(string) && Conversions.ContainsKey(to)) ||
- (to == typeof(string) && Conversions.ContainsKey(value.GetType())))
+ bool containsFrom = Conversions.ContainsKey(from);
+ bool containsTo = Conversions.ContainsKey(to);
+
+ if ((containsFrom && containsTo) ||
+ (from == typeof(string) && containsTo) ||
+ (to == typeof(string) && containsFrom))
{
try
{
@@ -125,10 +146,18 @@ namespace Perspex.Utilities
return false;
}
}
- else
+
+ var cast = from.GetRuntimeMethods()
+ .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to);
+
+ if (cast != null)
{
- return TryCast(to, value, out result);
+ result = cast.Invoke(null, new[] { value });
+ return true;
}
+
+ result = null;
+ return false;
}
///
diff --git a/tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs b/tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs
index 59b0d1c422..b438d6af1d 100644
--- a/tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs
+++ b/tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs
@@ -32,6 +32,18 @@ namespace Perspex.Markup.UnitTests
Assert.Equal(5.0, result);
}
+ [Fact]
+ public void Can_Convert_String_To_Enum()
+ {
+ var result = DefaultValueConverter.Instance.Convert(
+ "Bar",
+ typeof(TestEnum),
+ null,
+ CultureInfo.InvariantCulture);
+
+ Assert.Equal(TestEnum.Bar, result);
+ }
+
[Fact]
public void Can_Convert_Double_To_String()
{
@@ -43,5 +55,50 @@ namespace Perspex.Markup.UnitTests
Assert.Equal("5", result);
}
+
+ [Fact]
+ public void Can_Convert_Double_To_Int()
+ {
+ var result = DefaultValueConverter.Instance.Convert(
+ 5.0,
+ typeof(int),
+ null,
+ CultureInfo.InvariantCulture);
+
+ Assert.Equal(5, result);
+ }
+
+ [Fact]
+ public void Can_Use_Explicit_Cast()
+ {
+ var result = DefaultValueConverter.Instance.Convert(
+ new ExplicitDouble(5.0),
+ typeof(double),
+ null,
+ CultureInfo.InvariantCulture);
+
+ Assert.Equal(5.0, result);
+ }
+
+ private enum TestEnum
+ {
+ Foo,
+ Bar,
+ }
+
+ private class ExplicitDouble
+ {
+ public ExplicitDouble(double value)
+ {
+ Value = value;
+ }
+
+ public double Value { get; }
+
+ public static explicit operator double (ExplicitDouble v)
+ {
+ return v.Value;
+ }
+ }
}
}