1

I have to read/write an XML file that stores its data as bit masked values.

e.g.

<panel>
    <options arming="21" opt_b="51" opt_c="6" />
</panel>

in this case, arming has the value 21, but this corresponds to the following string of bytes:

10101

and those bytes correspond to options 0,2,4 in the following list:

  • Bit 0: Forced arm
  • Bit 1: Final door
  • Bit 2: Exit fault
  • Bit 3: Inhibit tamper
  • Bit 4: Display
  • Bit 8: Rearm
  • Bit 9: Line
  • Bit 10: Extend block

What's the best way for me to

  • convert this from the decimal value of 21 to an object model that represents the options?
  • use that object to display these as options for the user to select and deselect?
DaveDev
  • 41,155
  • 72
  • 223
  • 385

2 Answers2

3

Declare an enum thus:

[Flags]
public enum ArmingFlags {
   None=0
   Forced_arm = 1
   Final_door = 2
   Exit_fault = 4
   Inhibit_tamper = 8
   Display = 16
   Rearm = 32
   Line = 64
   Extend_block = 128
}

Note my use of powers of two in the enum. These allow an enum to represent discrete values using binary bit positions (see Why do enum permissions often have 0, 1, 2, 4 values?)

then parse your value into an integer and cast that to a type of ArmingFlags (note, untested code ahead but should work):

ArmingFlags flagsVal = ArmingFlags.None;
Int32 val;
if (Int32.TryParse(armingString, out val)) {
    flagsVal = (ArmingFlags)val;
}

// Then you can test it for expected values:
if ((flagsVal & ArmingFlags.Rearm) == ArmingFlags.Rearm) {
    //The Rearm bit was set...
}

There are lots of posts on how to use an enum in a WPF combobox or radio buttons, for instance:

Databinding an enum property to a ComboBox in WPF

Community
  • 1
  • 1
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • Thanks, this worked. Note - I've edited the answer to add some brackets. Just wondering though, why write `((flagsVal & ArmingFlags.Rearm) == ArmingFlags.Rearm)`? Wouldn't `(flagsVal == ArmingFlags.Rearm)` work just the same? It seems redundant, but I've seen a couple of other examples like that. It worked when I tested it with both examples though. – DaveDev Apr 03 '12 at 15:51
  • You want to test for a single flag amongst (potentially) multiple flags. For instance, the value you showed in the OP (10101) is not equal to ArmingFlags.Forced_arm (it is `ArmingFlags.Forced_arm & ArmingFlags.Exit_fault & ArmingFlags.Display`). To test the specific flag bit you need to filter out all of the other 1's in the value and then perform the equality test. – Chris Shain Apr 03 '12 at 16:06
  • Really it is best explained in the post I linked above: http://stackoverflow.com/questions/9811114/why-do-enum-permissions-often-have-0-1-2-4-values/9811145#9811145 – Chris Shain Apr 03 '12 at 16:06
2

How about using the power of enums to help you along your way:

[Flags]
public enum AlarmData
{
    ForcedArm = 1,
    FinalDoor = 2,
    ExitFault = 4,
    InhibitTamper = 8,
    Display = 16,
    Rearm = 32,
    Line = 64,
    ExtendBlock = 128
}

private static Dictionary<AlarmData, string> alarmDataLookup = new Dictionary<AlarmData, string>
{
    { AlarmData.ForcedArm, "Forced arm" },
    { AlarmData.FinalDoor, "Final door" },
    { AlarmData.ExitFault, "Exit fault" },
    { AlarmData.InhibitTamper , "Inhibit tamper" },
    { AlarmData.Display , "Display" },
    { AlarmData.Rearm , "Rearm" },
    { AlarmData.Line , "Line" },
    { AlarmData.ExtendBlock , "Extend block" }
};

public IEnumerable<string> EnumerateValues(AlarmData data)
{
    return from pair in alarmDataLookup 
            where data.HasFlag(pair.Key) 
            select pair.Value;
}

Calling the EnumerateValues is simple once you've read out the value from the XML, just cast the integer as the AlarmData enum, e.g.:

int value = GetAlarmValueFromXml();
var bindableValues = EnumerateValues((AlarmData)value);

Of course, you don't have to return strings from the EnumerateValues method. All you would then need to do is bind the result of the method to a list or some other element, and Bob's your uncle.

Mike Goatly
  • 7,380
  • 2
  • 32
  • 33