@virtualolympus posted a great bitwise enum binding solution in response to my sateful-converter-hack and it looks like a really nice clean solution. If you’re a WPF/XAML developer, definitely check it out.
When you find yourself writing entire helper classes – or worse – implementing hacks, it’s time to admit that XAML / MVVM needs better Enum support! Until then @virtualolympus‘ solution is the best I’ve seen.
Ok, I admit it – I did work out another hack for this problem this morning :D Hack hack hack! If you’re stuck on a pre-dynamic framework and still left wondering how to easily bind to a bitwise flag, this might actually be viable.
First examine these CheckBox bindings and note the ConverterParameter:
<CheckBox IsChecked="{Binding EditingSpecies.Flags, Converter={StaticResource BitwiseToBool}, ConverterParameter=1|A}" Content="BreathesAir"/>
<CheckBox IsChecked="{Binding EditingSpecies.Flags, Converter={StaticResource BitwiseToBool}, ConverterParameter=2|A}" Content="BreathesWater"/>
We’re supplying two values to the Converter, separated by pipe. The first value is of the bit flipped by this CheckBox; the other value is a “group” name. You can call the group whatever you want (“A” was arbitrary) so long as the same group name is used on all CheckBoxes flipping bits for a Flag.
The Converter uses the contextual group name to maintain the state (value) of the bitwise Flag without tainting the converter with too much inappropriate context. The result is a more generic/versatile/orthogonal bitwise Converter:
public class BitwiseToBool : IValueConverter
{
Dictionary<string, Int64> EnumStates = new Dictionary<string, Int64>();
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string[] parms = parameter.ToString().Split('|');
Int64 flipbit = Int64.Parse(parms[0]);
//statekey = parms[1]
Int64 enumvalue = System.Convert.ToInt64(value);
if (!this.EnumStates.ContainsKey(parms[1]))
this.EnumStates.Add(parms[1], enumvalue);
else
this.EnumStates[parms[1]] = enumvalue;
return (enumvalue & flipbit) != 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string[] parms = parameter.ToString().Split('|');
Int64 flipbit = Int64.Parse(parms[0]);
//statekey = parms[1]
Int64 enumvalue = this.EnumStates[parms[1]];
if ((bool)value)
enumvalue |= flipbit;
else
enumvalue &= ~flipbit;
this.EnumStates[parms[1]] = enumvalue;
return Enum.Parse(targetType, enumvalue.ToString());
}
}
But it has 2 design faux pas:
- It requires knowledge of ConverterParameter “hidden magic”, i.e. keying the ConverterParameter with a group name.
- It somewhat technically violates SPOT/DRY. The Flag value on both the VM and in the Converter need to remain reliably synchronized.
So that now gives us 2 dubious-but-simple ways to bind to a bitwise enum, plus 1 really-good-but-requires-dynamicobjects way. Programming is fun!
Today I finally found the GetChangeSet problem: I failed to new-up an EntitySet… that’s all it was (at least it was an easy fix).
With that, Species are in! This thing is almost done! Just need to add Compounds & Elements. Share in my Database editing joy…
Bonus content! The Arsanth Database Editor theme song!
