The power of XAML databinding is continually nudging me to rethink how I design view-model classes. The latest nudge came when I was working with Windows Presentation Foundation (WPF) and a domain object that contained several related Boolean attributes. At first, I’d thought of creating a view-model class with a property for each attribute; but previous experience with such a view-model had convinced me that such designs were cumbersome. That’s when it occurred to me to use .NET’s flag enumerations. This article discusses such an implementation, as well as some technical lessons that I learned in the process.
The sample code for this article manages a few dog properties as shown in the below form.
Before we begin though, allow me a warning to both dog lover and software architect. My aptly named “Demonstration” solution may fall short in a few areas of personal and professional preference, but no dogs were harmed in the process.
Enumerated FLAGS 101
To work with flag enum classes, you need to understand what makes them different from their more prevalent, non-flag brethren. By doing so, you’ll not only augment your coding toolbox, but possibly also improve your view, and view-model, designs.
Definition
Plain old enums (POE?), to quote MSDN, are “a distinct type consisting of a set of named constants called the enumerator list”. You can use any integral type except a char as values for a POE. The CLR’s System-defined [FLAGS] class attribute adds a powerful twist to an enum class. It informs the runtime that the underlying value types now support bitwise operations.
Why Enums?
Truth be told, enums could qualify as syntax sugar as indicated by their omission from the earlier versions of C. Even so, they now exist in most modern programming languages because they allow you to share a multi-valued property across applications.
Imagine if .NET did not support enumerations. Consider the System.IO’s FileOpen method which includes two FileMode and FileAccess enumerations. How would you rewrite FileOpen without them? Create several new methods, such as, FileOpenCreateNewReadWrite or FileOpenRead? Our new API begins to look unwieldy and maybe a little ugly.
The below side-by-side comparison from the Demonstration solution highlights our two different enumerations.
At first blush they look similar except for the [FLAGS] attribute, which requires the System namespace declaration. Closer examination reveals that the DogProperties‘ values grow as powers of 2. This is not accidental. The pattern allows for binary calculations, as explained shortly, which enables treating an enumerated property as collection of values as shown in the below code snippet.
A Bit of Math
Underneath the covers .NET knows two things about flag enumerations. First, individual enumerated values equal a binary digit, 0 or 1. Second, each individual enumerated value resides in one and only position in a binary number. The following expressions of a DogProperties that includes both Big and Loud values illustrates these two facts at work.
Expressed as an Enum
DogProperties.Big | DogProperties.Loud
Expressed as a sum of 2x
0 * 25 + 0 * 24 + 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 + 0
Expressed as a sum of binary digits
00000 + 00000 + 00100 + 00000 + 00010 + 00000 + 0
Expressed as a binary digit
001010
Once you appreciate this bit mapping, then you’ll quickly see that it only requiresa line of codeto determine whether or not our Dog is loud.
Checking FLAG Enum Property in C#
(Dogproperties & DogProperties.Loud) == Dogproperties.Loud
Checking Property in Binary
001010
& 001000
001000 == 001000
Caveats
The FLAG enums have gained a reputation for being difficult. Why? While binary calculations are not inherently tricky, they may trip developers up when they try to combine them, or to perform logical comparisons. For example, do I use an ampersand or pipe character when adding a new value? Which one do I use for checking a logical equality? Recent enhancements in .NET’s languages can minimize these frustrations, as we will see shortly.
The second hazard is not so easily waved away with magic. The maximum number of Boolean values that are available to a flag enumeration is small. Typically .NET enumerations ride upon 32-bit integers and the FLAG restriction limits those values to sets supporting binary operations. These two constraints conspire together to limit the maximum uncombined properties in a flag enumeration to thirty.
Why only 30 FLAGs?
The math behind the FLAGS enum type’s 30 value limitation is exponential. Calculate the base 2 log of the enumerated value type’s maximum. Applying this formula to a default .NET enum type equates to log2 (2,147,483,647) or an integer less than 30.999999999328196.
This limitation jives with our newfound understanding that 31 values for a FLAG enum type demands the largest value equal 231 or 2,147,483,648 which exceeds .NET’s int.MaxValue.
The Demonstration Solution
It is easy to introduce flag enums into our solution – you just add the DogProperties enum type and add a few values. The real challenge comes in making them easy to code in a XAML world. For our situation, two supporting classes seem to do just that. The first uses .NET extensions to simplify the task of manipulating DogProperties. The other facilitates communications between XAML and the view-model’s DogProperties property.
Extensions
While coding a .NET extension method may not be intuitive at first, it is at least formulaic. Create a static class; add a static method; append “this” to the first parameter which is same type as target; and code the body. The below snippet is an example of a basic extension method.
I suspect that few developers find anything complex within this method’s body. It just executes a binary operation that removes a dogProperty from dogProperties. The more germane question is this: ‘which of the following lines of code would you prefer writing when in a rush?’
There is a great advantage in using extensions to place domain-specific business rules in one spot when you are working with FLAG enums. Look at the below AddValue method. It applies a few domain rules that could be easily overlooked by developers working directly with DogProperties.
IValueConverter
WPF developers quickly encounter another one of those little XAML annoyances when binding view-models’ to an enum-based property. It doesn’t work. XAML’s designers fortunately predicted problems like this and so they created IValueConverter. Our demonstration solution implements this interface with a slight twist as show below.
DogPropertiesConverter relies heavily on the parameter parameter (that’s not a typo). Most converters ignore parameter and work with value. Parameter equates to ConverterParameter property value of the converter’s binding markup. In our case it helps differentiate several XAML controls bound to our view-model’s DogProperties property.
Another interesting aspect of the converter code is the inclusion of Enum.TryParse. While such checks are not mandatory they can prove helpful when debugging. For example, the TryParse within the ConvertBack method quickly notifies a developer if they mistyped a markup’s ConverterParameter enumerated DogProperties string value. Would you readily spot the error below?
Error Hint: Look at the ConverterParameters‘ values. Dogs are either ‘Big’ or ‘Small’.
IConverterValue Mechanics
Our discussion glosses over IValueConverter implementation details. Read MSDN’s IValueConverter Interface page for the specifics of rolling your own.
All Together
Our handiwork finally comes together starting with the Dog view-model and wraps up with the MainWindow view.
To implement the DogProperties property, you just need to add it to the Dog class as shown in the following snippet. Remembering that view-model classes exist to ease the interaction between the user interface and its models guides our property set’s body. It implements two desired behaviors as shown in the following snippet.
The first behavior that the setter tackles is the one that enables developers to initialize DogProperties by passing the Undefined enumerated value. This skips the binary calculations hidden within the extension methods that do not understand the idea of allowing one value to wipe away all others. (Didn’t we mention FLAG enums could be tricky?)
Next, the setter updates the state based on both the provided value and current state. If the value already exists in DogProperties, it is removed, if it doesn’t exist, it is added. For example, if DogProperties already included DogProperties.Big, then you can remove it by reapplying this value to the view-model. This behavior seems odd, but it allows databound XAML controls to effortlessly flip a specific DogPropertys’ attribute between true and false values.
Building MainWindow is the last implementation task. With all the ground-work complete, then coding proceeds like many other view-models’ views so we need not discuss it in detail. A quick peek at the code-behind, though, reminds us how easy it can be working with FLAG enumerations, compared with using a bunch of separate properties.
Lessons from the Field
It is not exactly easy to Implement FLAG enumerated values in the real world. The task is not without challenges. Yet, there are also some advantages.
Reducing the property count is by far the biggest positive result of FLAG enumerated class properties. One integer property serializes quicker and smaller than several Boolean properties. And, as a result, they move over the wire faster and take up less space in a database.
Reducing the property count is by far the biggest downside of FLAG enumerated class properties. It requires complex or custom code to manipulate them, and this can easily translate into bugs. For example, writing SQL for updating an integer column that equates to several Boolean combinations is not a trivial set operation.
Many .NET developers have not worked FLAG enumerations. While our Demonstration solution may help to flatten the learning curve, be prepared to show n’ tell the flag.
It isn’t that easy to introduce extension methods into an application according to the blogosphere. Most of these issues can be avoiding with a few patterns. Firstly, create generic FLAG enumeration helpers with caution; best targeting them to specific enums. Second, keep extensions “near” their enums. If developers can add a reference to an enum without the supporting extension methods, then they are unlikely to use them (until after code reviews).
Finally, try to avoid using a FLAG enumeration as a grab-bag of unrelated properties. You can, but you shouldn’t. Our approach certainly supports this design choice but the mishmash will confuse developers. Would you want to write XAML binding a dozen logically unrelated controls to one property entitled Stuff?
Conclusion
This article discussed a set of ideas for implementing flag enumerations within a WPF application using view-models. Many technical and architectural variations exist. For example, I recently saw an application cleverly exploiting an IMultiValueConverter class instead of IValueConverter for passing enumerations between view and view-model.
Whether or not you incorporate flag enumerations into your next XAML application remains just another one of your many design options. I do hope though after reading this article that one of those decisions just got a little easier.
Load comments