Skip to content

Commit

Permalink
fix for BoolToVisibility conversion: Custom types with defined implic…
Browse files Browse the repository at this point in the history
…it cast to bool are unsupported by BoolToVisibility converter Alex141#53
  • Loading branch information
rstroilov committed Feb 3, 2018
1 parent f337da8 commit 0ab01e0
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
34 changes: 34 additions & 0 deletions CalcBinding/BoolToVisibilityConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;

Expand All @@ -22,6 +25,17 @@ public BoolToVisibilityConverter(FalseToVisibility falseToVisibility)

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var valueType = value.GetType();

if (valueType != typeof(bool))
{
var implicitConverter = GetImplicitConversion(valueType, typeof(bool));
if (implicitConverter != null)
{
value = implicitConverter.Invoke(null, new object[] { value });
}
}

if ((bool)value)
return Visibility.Visible;

Expand All @@ -34,5 +48,25 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
}

public FalseToVisibility FalseToVisibility { get; set; }

private static MethodInfo GetImplicitConversion(Type baseType, Type targetType)
{
return GetAllImplicitCasts(baseType, targetType)
.FirstOrDefault();
}

private static IEnumerable<MethodInfo> GetAllImplicitCasts(Type baseType, Type targetType)
{
var currentTypeMethods = baseType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(x => x.Name == "op_Implicit" && x.ReturnType == targetType)
.ToList();

while (baseType != typeof(object) && !currentTypeMethods.Any())
{
return GetAllImplicitCasts(baseType.BaseType, targetType);
}

return currentTypeMethods;
}
}
}
40 changes: 32 additions & 8 deletions Tests/BoolToVisibilityConverterTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
using CalcBinding;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Tests
Expand All @@ -16,8 +11,6 @@ public class BoolToVisibilityConverterTests
[TestMethod]
public void ConvertBoolToVisibilityTest()
{
var converter = new CalcConverter();

Assert.AreEqual(Visibility.Visible,
new BoolToVisibilityConverter()
.Convert(true, typeof(Visibility), null, CultureInfo.CurrentCulture));
Expand Down Expand Up @@ -45,6 +38,37 @@ public void ConvertVisibilityToBoolTest()
Assert.AreEqual(false,
new BoolToVisibilityConverter()
.ConvertBack(Visibility.Hidden, typeof(bool), null, CultureInfo.CurrentCulture));
}
}

[TestMethod]
public void ConvertsCastableToBoolWhenValueHasImplicitConversion()
{
Assert.AreEqual(Visibility.Visible,
new BoolToVisibilityConverter()
.Convert(new CastableToBoolean(true), typeof(Visibility), null, CultureInfo.CurrentCulture));

Assert.AreEqual(Visibility.Collapsed,
new BoolToVisibilityConverter()
.Convert(new CastableToBoolean(false), typeof(Visibility), null, CultureInfo.CurrentCulture));

Assert.AreEqual(Visibility.Hidden,
new BoolToVisibilityConverter(FalseToVisibility.Hidden)
.Convert(new CastableToBoolean(false), typeof(Visibility), null, CultureInfo.CurrentCulture));
}

private sealed class CastableToBoolean
{
private bool value;

public CastableToBoolean(bool value = false)
{
this.value = value;
}

public static implicit operator bool(CastableToBoolean obj)
{
return obj.value;
}
}
}
}

0 comments on commit 0ab01e0

Please sign in to comment.