Click here to Skip to main content
Click here to Skip to main content

WPF/Silverlight Binding Using Flags Class

, 8 Jul 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
A special class is needed to support binding a set of flags to a View.

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 View-Model. 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 View-Model to support the View, and so have often used Value Converters to determine if a value is null and convert this to a Boolean or Visibility property to enable or hide controls. I also like to use a state enumeration with a Value Converter 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) checkboxes were selected, there would be lines with arrowheads and the lines would connect adjacent checkboxes and checkboxes 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:

/// <span class="code-SummaryComment"><summary>
</span>/// Counts number of flags set
/// <span class="code-SummaryComment"></summary>
</span>/// <span class="code-SummaryComment"><returns>number of flags set</returns>
</span>public int Count
{
    get
    {
        int count = 0;
        uint n = (uint)flags;
        while (n != 0)
        {
            count++;
            n &= (n - 1);
        }
        return count;
    }
}

/// <span class="code-SummaryComment"><summary>
</span>/// value of flag for highest value flag set
///      -1 if nothing set
/// <span class="code-SummaryComment"></summary>
</span>/// <span class="code-SummaryComment"><returns>value of flag for highest value flag set</returns>
</span>public int Max
{
    get
    {
        if (flags == 0) return -1;
        uint v = (uint)flags;
        int result = 0;
 
        for (int i = 4; i >

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
/// <span class="code-SummaryComment"><summary>
</span>/// Returns true is particular flag is set, otherwise false
/// <span class="code-SummaryComment"></summary>
</span>public object Convert(object value, Type targetType, object parameter, 
              System.Globalization.CultureInfo culture)
{
    if (TrueValue == null)
    {
        // If TrueValue and FalseValue have not been set,
        // create defaults of boolean True and False
        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;
}
 
/// <span class="code-SummaryComment"><summary>
</span>/// Returns Flag instance to be used to set or reset value in Flag class
///      Use Flag.ProcessFlag(flag) in property to handle change
/// <span class="code-SummaryComment"></summary>
</span>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))
    {
        // Note that return is actually special instance of flag used to pass
        // information about which value is affected, and if to set or reset
        return new BindingFlags(p, (bool)value);
    }
    // else return an empty flag element
    return new BindingFlags();
}
 
/// <span class="code-SummaryComment"><summary>
</span>/// Value return from Convert method if value is set
/// <span class="code-SummaryComment"></summary>
</span>public object TrueValue { get; set; }
 
/// <span class="code-SummaryComment"><summary>
</span>/// Value return from Convert method if value is not set
/// <span class="code-SummaryComment"></summary>
</span>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
    {
        // in this case just force update, then check if there is a change
        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 TextBlocks 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"));
            }
 
            // This line will ensure that no GraphicFlags are set if the
            // corresponding TestFlag is not set. Use existing GraphicsFlags 
            // code to check for changes.
            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 an 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Clifford Nelson
Software Developer (Senior) ETeam/Delloitte
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last three years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with NBC Universal in Universal City, CA

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 8 Jul 2011
Article Copyright 2011 by Clifford Nelson
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid