Skip to content

Instantly share code, notes, and snippets.

@haavamoa
Last active February 21, 2019 07:38
Show Gist options
  • Save haavamoa/35d0064f72f3d4edc2d705433f2eed0c to your computer and use it in GitHub Desktop.
Save haavamoa/35d0064f72f3d4edc2d705433f2eed0c to your computer and use it in GitHub Desktop.
Awesome converter to use when you have a list of bools that you want to convert
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace MynameSpace
{
/// <summary>
/// A converter to run a logical gate on multiple boolean values <see cref="LogicalGate"/>.
/// Return value can be set by using <see cref="ReturnType"/>
/// </summary>
public class LogicalExpressionConverter : MarkupExtension, IMultiValueConverter
{
public LogicalGate LogicalGate { get; set; }
public ReturnType ReturnType { get; set; }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null)
{
switch (ReturnType)
{
case ReturnType.Visibility:
return Visibility.Collapsed;
case ReturnType.Boolean:
return false;
case ReturnType.Undefined:
return Visibility.Collapsed;
}
}
foreach (var value in values)
{
if(value == DependencyProperty.UnsetValue || value == null)
{
switch (ReturnType)
{
case ReturnType.Visibility:
return Visibility.Collapsed;
case ReturnType.Boolean:
return false;
case ReturnType.Undefined:
return Visibility.Collapsed;
}
}
}
try
{
List<bool> bools = values.Cast<bool>().ToList();
bool logcalExpression = false;
switch (LogicalGate)
{
case LogicalGate.Undefined:
throw new ArgumentException($"LogicalConverter undefined property: {nameof(LogicalGate)}");
case LogicalGate.And:
logcalExpression = bools.All(b => b);
break;
case LogicalGate.Nand:
logcalExpression = bools.All(b => !b);
break;
case LogicalGate.Or:
logcalExpression = bools.Any(b => b);
break;
case LogicalGate.Nor:
logcalExpression = bools.Any(b => !b);
break;
default:
throw new ArgumentOutOfRangeException();
}
switch (ReturnType)
{
case ReturnType.Boolean:
return logcalExpression;
case ReturnType.Visibility:
return logcalExpression ? Visibility.Visible : Visibility.Collapsed;
case ReturnType.Undefined:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
catch (Exception e)
{
throw new Exception("LogicalExpressionConverter : Something went wrong while converting:", e);
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException("EmbeddedBrowser : LogicalExpressionConverter does not support convert back");
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace MyNameSpace
{
[TestClass]
public class LogicalExpressionConverterTests
{
private LogicalExpressionConverter m_cut;
[TestInitialize]
public void BeforeEachTest()
{
m_cut = new LogicalExpressionConverter();
}
[TestMethod]
public void Convert_ValuesAreNull_NegativeResult()
{
var convertedBoolValue = (bool)Convert(null, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(null, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_OneValueIsNull_NegativeResult()
{
var values = new object[] {true, true, null};
var convertedBoolValue = (bool)Convert(values, returnType:ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_OneValueDependencyPropertyUnsetValue_NegativeResult()
{
var values = new[] { true, true, DependencyProperty.UnsetValue };
var convertedBoolValue = (bool)Convert(values, returnType:ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_UndefinedLogicalGate_ThrowsException()
{
var values = new object[] { true, true, true};
try
{
Convert(values);
Assert.Fail();
}
catch (Exception e)
{
if (!(e.InnerException is ArgumentException))
{
Assert.Fail();
}
}
}
[TestMethod]
public void Convert_AndLogicalGate_AllValuesTrue_PositiveResult()
{
var values = new object[] { true, true, true };
var convertedBoolValue = (bool)Convert(values, logicalGate:LogicalGate.And, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.And, returnType: ReturnType.Visibility);
Assert.IsTrue(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Visible);
}
[TestMethod]
public void Convert_AndLogicalGate_OneValueFalse_ReturnTypeBoolean_IsFalse()
{
var values = new object[] { true, true, false };
var convertedBoolValue = (bool)Convert(values, logicalGate:LogicalGate.And, returnType:ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.And, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_NandLogicalGate_NoValuesAreTrue_PositiveResult()
{
var values = new object[] { false, false, false };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Nand, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Nand, returnType: ReturnType.Visibility);
Assert.IsTrue(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Visible);
}
[TestMethod]
public void Convert_NandLogicalGate_OneValueIsTrue_NegativeResult()
{
var values = new object[] { false, true, false };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Nand, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Nand, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_OrLogicalGate_OneValueIsTrue_PositiveResult()
{
var values = new object[] { false, true, false };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Or, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Or, returnType: ReturnType.Visibility);
Assert.IsTrue(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Visible);
}
[TestMethod]
public void Convert_OrLogicalGate_AllValuesAreFalse_NegativeResult()
{
var values = new object[] { false, false, false };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Or, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Or, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
[TestMethod]
public void Convert_NorLogicalGate_OneValueIsFalse_PositiveResult()
{
var values = new object[] { true, false, true };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Nor, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Nor, returnType: ReturnType.Visibility);
Assert.IsTrue(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Visible);
}
[TestMethod]
public void Convert_NorLogicalGate_AllValuesAreTrue_NegativeResult()
{
var values = new object[] { true, true, true };
var convertedBoolValue = (bool)Convert(values, logicalGate: LogicalGate.Nor, returnType: ReturnType.Boolean);
var convertedVisibilityValue = (Visibility)Convert(values, logicalGate: LogicalGate.Nor, returnType: ReturnType.Visibility);
Assert.IsFalse(convertedBoolValue);
Assert.AreEqual(convertedVisibilityValue, Visibility.Collapsed);
}
private object Convert(object[] values, LogicalGate logicalGate = LogicalGate.Undefined, ReturnType returnType=ReturnType.Undefined)
{
m_cut.LogicalGate = logicalGate;
m_cut.ReturnType = returnType;
return m_cut.Convert(values, null, null, null);
}
}
}
namespace MynameSpace
{
public enum LogicalGate
{
Undefined, //Default, non-existing logical expression
And,
Nand,
Or,
Nor
}
}
<Separator IsTabStop="False">
<!-- Shows the separator if first, second or thrid element is visible -->
<Separator.Visibility>
<MultiBinding Converter="{Converters:LogicalExpressionConverter LogicalGate=Or, ReturnType=Visibility}">
<Binding ElementName="MyFirstElement"
Path="IsVisible" />
<Binding ElementName="MySecondElement"
Path="IsVisible" />
<Binding ElementName="MyThirdElement"
Path="IsVisible" />
</MultiBinding>
</Separator.Visibility>
</Separator>
namespace MyNameSpace
{
public enum ReturnType
{
Undefined, //Default, non-existing return type
Visibility,
Boolean,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment