Introduction
A flag enumeration is a very useful tool in programming. However, it is not straightforward to use flags in binding. Somehow or another, the particular flag has to be specified. This is possible using the binding "parameter". With this information, it is quite straightforward to convert for the View, but the problem is converting back. You would normally be binding to a checkbox and this value is either true or false (tri-state does not make sense). When converting back, there is no information about the state of the other flags. Without this information, it is not possible to update the flags value in the ViewModel
. This is one of the main reasons a special class is needed to support binding a set of flags to a View
. Once there is an implementation to support flags in both WPF and Silverlight, implementations can be much cleaner.
Description
When I develop WPF (or Silverlight) applications, I like to minimize the properties I need in the ViewModel
to support the View
, and so have often use an IValueConverter
to determine if a value is null
and convert this to a bool
or Visibility
property to enable or hide controls. I also like to use a state enumeration with an IValueConverter
to change the look of the UI. I also will have a state enumeration and then use the state name in the parameter when binding to the state enumeration instance.
I had a case where I had a CheckBox
collection that could be enabled or disabled. When multiple (enabled) CheckBox
controls were selected, there would be lines with arrowheads and the lines would connect adjacent CheckBox
cotnrols and CheckBox cotnrols separated by unchecked checkboxes. A graphic was associated to the left of each checkbox. The graphic consisted of two quarter circles, one curving from the left up, and the other curving left down from the same starting point. There was an arrow head pointing left, with its tip being at the starting point of both curves. Then there was a line the connected the separated ends of the two quarter circles. By hiding or showing each of these graphic elements, it was possible to connect all the checkboxes together, with lines ending in an arrowhead. I wanted a clean way to implement this UI.
I used two integers with a bit representing each checkbox and the associated graphic. One integer was used to control if each checkbox was enabled; the other indicated the checkboxes' checked state. This second integer was used to control the graphics. To do the binding, the Parameter
attribute of the binding was used, each CheckBox
and associated graphic using a specific integer for all bindings. The graphic would be bound to the integer value that indicates the checked states for all checkboxes, and thus could determine if the associated CheckBox
was checked, and if it was associated with the maximum or minimum value checkbox, or if it was outside the maximum and minimum (arrowheads either went up or down, not both). Check the code for the graphic in the example to get the details of how this was done.
Originally, I created a lot of inline code, but knew this was not the perfect solution. A better solution was to create a class that encapsulated all of this functionality.
As an example of using a flag enumeration that was bound to a checkbox collection, I used two checkbox collections, the first to enable or disable a checkbox in the second collection. Setting a particular checkbox would enable checkbox in a collection that was in a mirror of the first checkbox collection. This second checkbox would set a value on another flag enumeration that would control a graphic. The graphic was bound to the same flag enumeration as the second checkbox collection to get the graphic to correctly connect the second checkbox collection. (Note: I have included a graphic associated with the first checkbox collection to show binding using the Value
property of the BindingFlags
class to show how I initially solved the problem, and the code is in the Graphics
class to support binding to the Value
property instead of an instance of the BindingFlags
class.)
As implemented, I use an unsigned integer to store the flags. This will support 32 flags, which should satisfy most scenarios; a short integer would not meet more cases and would not have provided much benefit in processing or memory.
For the functionality, I needed to calculate information about the flags as a whole: the minimum set flag value and the maximum set flag value. There are some efficient ways of calculating attributes of bits in an integer, but the algorithms are not obvious. This is a reason for encapsulating the functionality in a class. I implemented the functions as properties so that they can be used directly for binding. This also has another benefit in that the bindings for these functions will be updated when the PropertyChanged
event for the instance of the BindingFlags
class is raised. Some of the somewhat costly processing flag functions I needed and wanted to be efficient was calculating the count of set flags, the maximum flag value, and the minimum flag value:
public int Count
{
get
{
int count = 0;
uint n = (uint)flags;
while (n != 0)
{
count++;
n &= (n - 1);
}
return count;
}
}
public int Max
{
get
{
if (flags == 0) return -1;
uint v = (uint)flags;
int result = 0;
for (int i = 4; i >= 0; i--) {
if ((v & MaxFunctionFlagsMasks[i]) > 0)
{
v >>= MaxMinFunctionBitShiftArray[i];
result |= MaxMinFunctionBitShiftArray[i];
}
}
return result;
}
}
public int Min
{
get
{
if (flags == 0) return -1;
uint v = (uint)flags;
int result = 0;
for (int i = 4; i >= 0; i--) {
if ((v & MinFunctionFlagsMasks[i]) == 0)
{
v >>= MaxMinFunctionBitShiftArray[i];
result |= MaxMinFunctionBitShiftArray[i];
}
}
return result;
}
}
private static uint[] MaxFunctionFlagsMasks = { 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000 };
private static int[] MaxMinFunctionBitShiftArray = { 1, 2, 4, 8, 16 };
private static uint[] MinFunctionFlagsMasks = { 0x1, 0x3, 0xF, 0xFF, 0x0000FFFF };
I incorporated the IValueConverter
functionality within the same class just to keep all the code together, and to eliminate the need to have more exposed variables. There are several variables inside the BindingFlags
class that are used specifically for the IValueConverter
, and there is a constructor to support the IValueConverter
that is private so can only be used by the class. There is obviously a cost of memory for using the same class for two functions, and maybe people who use the class may want to break out the IValueConverter
code. The IValueConverter
takes a parameter which is the flag number, with flag representing the least significant bit being ‘0’, and the flag for the most significant bit being ‘31’. When converting to a bool for the flag, just use the parameter as the flag index, and return a bool to indicate if the flag is set. When converting back, a BindingFlags
instance is created using a special constructor that sets a flag to indicate that this is a special instance of BindingFlags
. Then using the DependencyPropertyUpdate
in a BindingFlags
property in the ViewModel, the DependencyPropertyUpdate
method uses the flag value to indicate which flag (could be multiple flags, but this feature is not used) is changed. Another feature of the IValueConverter
code is that the returned true and false values can be specified when the IValueConverter
is declared in the XAML. The default is a bool true and false, respectively. Note: that only the TrueValue
is checked in the IValueConverter
code, and, if so, both TrueValue
and FalseValue
are set to the defaults. In the example, I use this feature to pass either Visibility.Collapsed
or Visibility.Visible
using the instance that is labeled FlagVisibilityConverter
.
The following is the IValueConverter
code:
#region IValueConverter
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (TrueValue == null)
{
TrueValue = true;
FalseValue = false;
}
BindingFlags f = value as BindingFlags;
int p;
if (f != null & int.TryParse(parameter.ToString(), out p))
{
return (f[p] ? TrueValue : FalseValue);
}
return FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
int p;
if (value is bool && int.TryParse(parameter.ToString(), out p))
{
return new BindingFlags(p, (bool)value);
}
return new BindingFlags();
}
public object TrueValue { get; set; }
public object FalseValue { get; set; }
#endregion
When creating a BindingFlags
class property for binding, the following code is used:
public BindingFlags Flags
{
get { return _Flags; }
set
{
if (value.DependencyPropertyUpdate(ref _Flags))
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Flags"));
}
}
}
}
private BindingFlags _GraphicFlags;
The DependencyPropertyUpdate
method takes a single reference argument of BindingFlags
. This has to be a reference argument so that the instance of BindingFlags
can be changed. This is required to force the bindings to update. If just a field or property in BindingFlags
is updated, then there would be no change event triggered because the code does not recognize that there has been a change in the variable (Microsoft, it would be nice if changing the GetHashCode()
return value would force a binding recalculate). Also, I ensure that neither of the two BindingFlags
instances is changed by this method. The bool return value is used to check if the PropertyChanged
event should be triggered.
The following is the code used to update a flag value with a return type of bool, which is true if any of the flags were changed:
public bool DependencyPropertyUpdate(ref BindingFlags f)
{
if (isSpecialInstance)
{
uint localFlag;
if (isSpecialInstanceSet)
localFlag = flags | f.flags;
else
localFlag = f.flags & (flags ^ (uint)0xFFFFFFFF);
if (localFlag == f.flags)
return false;
f = new BindingFlags(localFlag);
return true;
}
else
{
BindingFlags orgFlag = f;
f = this;
return flags != orgFlag.flags;
}
}
Notice in this method the checking of the field isSpecialInstance
; if a special bool is set to indicate that the value in the flags field is to be used to set or reset the bits set in that flags field, the new BindingFlags
value is ORed with the current flag (this will force the specified flag to be set); otherwise, the BindingFlags
value is exclusive ORed with all ones and then ANDed with the flag value flag (this will force the specified flag to be reset). If the isSpecialInstanceSet
bool is true, then the bits are set, otherwise the bits are reset.
Inside the example, I attempted to show a number of ways that the binding could be used in addition to enabling and setting checkboxes, and controlling the graphic. I used it to make TextBlock
s visible when the associated checkbox was checked. Hopefully this pattern will be of use to others.
I also created a special Masked
method in the BindingFlags
class to apply a mask, which was also a BindingFlags
instance, to the flags field, and return the result as a BindingFlags
class. I needed some function to reset checkboxes in the second set when the corresponding checkbox was not set in the first set. All I needed to do was to use this to set the BindingFlags
instance controlling the graphics when there was a change in the BindingFlags
instance controlling the first set of checkboxes. The method returns an instance of BindingFlags
since I have to create a new instance of BindingFlags
to ensure the binding recognized that there had been a change.
public BindingFlags ControlFlags
{
get { return _ControlFlags; }
set
{
if (value.DependencyPropertyUpdate(ref _ControlFlags))
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ControlFlags"));
}
GraphicFlags = GraphicFlags.Masked(ControlFlags);
}
}
}
Points of Interest
I had a lot of trouble getting the binding to a property of BindingFlags
to work. After fixing a couple of bugs, I managed to convince myself that the code worked by binding to the Value
property. The code worked perfectly with this change in the View, but I thought was not too intuitive, and required some funny code in the class that created the graphic. I went back and made some changes, including setting a couple of the flags true initially, and discovered that the binding to an instance of the class was working, just the triggering the change logic was not. I attempted to just add the INotifyPropertyChanged
interface, and raising PropertyChanged
events inside the class, but that did not work. Also attempted to override Equals
and GetHashCode
; this also did not work. Inheriting from DependenyProperty
and DependencyObject
did not work either. It was only after a lot of frustrations that I finally figured out that what was needed to be done in the binding was creating a new instance of the BindingFlags
class when there is a change in the value.
I had another issue that I had to give thought to get working. I wanted to use the flags that enabled the second set of flags to ensure that a checkbox in the second set was unchecked if it was disabled. I was able to accomplish this by using a MultiValueConverter
, but the problem was that there was no way to convert back since again I did not have the first set of flags. Thus I was able to force a checkbox not to be set if the checkbox was disabled, but could not get the controlling BindingFlags
instance to update to correspond to the state of the checkbox, and thus the graphic would be in the wrong state. Also, of course, the BindingFlags
instance would be wrong. This could have been fixed by using the same multi-binding as the checkboxes, but the bound BindingFlags
instance would be wrong. This is why I created the Masked
method.
Summary
This solution is far from perfect, mostly because of the method of binding from the View to the View-Model requiring different code from normal binding, but it is not particularly more difficult than binding with a value type or string. Also, there is the need to create a new instance of the BindingFlags
class when its value is changed. The implementation requires an unusual value converter, using an instance of the BindingFlags
class in a different way than normal. Still, I do not believe that these issues are significant, and the class is an effective tool to more cleanly implement solutions in XAML binding.
Help: The graphic I use does not resize the way I would like. If somebody has a solution, I would appreciate it.