Saturday, June 5, 2010

User defined WPF ComboBox binds to a nullable boolean type

For some reason the project I am doing at the moment requires a ComboBox that displays 'Yes', 'No' which represent True and False respectively. Also in some cases it needs to have an empty option which means both True and False. A common example of this would be searching the Active or Inactive records, or all of them. It looks like this



It needs to be used many times in the project so I decide to write an user defined ComboBox. Let's call it BoolComboBox.

The BoolComboBox should have these functions:

1. It can be defined in XAML if it needs to display an empty option.
2. The code behind should be able to receive a nullable boolean type value regarding to the user selected value.
3. It can be defined a default nullable boolean type value in XAML.

Let's start the code.

First we define a class derives from ComboBox and bind it to a Dictionary. Please note that it is just for presenting and it does not include the usings and namespace. The solution can be downloaded at the end of this post.
public class BoolComboBox : ComboBox
{        
    private Dictionary BindItems = new Dictionary() 
    {
        {"Yes",true}, {"No",false}
    }; // The displayed values can be configurable
    public BoolComboBox()
    {
        InitialiseItems();
    }

    private void InitialiseItems()
    {
        this.ItemsSource = BindItems.Keys;
    }
}
The "Yes", "No" are hardcoded. We can make it configurable to let it display whatever we want. But here let's keep it simple.

Then for the first function in the list above, we need to define a boolean type dependency property, say HasEmptyOption.
public static readonly DependencyProperty HasEmptyOptionProperty =
 DependencyProperty.Register("HasEmptyOption", typeof(Boolean), typeof(BoolComboBox),
 new PropertyMetadata(false, OnHasEmptyOptionPropertyChanged));

private static void OnHasEmptyOptionPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
 BoolComboBox boolComboBox = source as BoolComboBox;

 if ((bool)e.NewValue)
  boolComboBox.BindItems.Add(string.Empty, null);
}

public bool HasEmptyOption
{
 get { return (bool)GetValue(HasEmptyOptionProperty); }
 set { SetValue(HasEmptyOptionProperty, value); }
}
In the Event method it decides to add the empty option or not.

For function two we have another dependency property, a nullable boolean type named ReturnedValue.
public static readonly DependencyProperty ReturnedValueProperty =
 DependencyProperty.Register("ReturnedValue", typeof(Boolean?), typeof(BoolComboBox),
 new PropertyMetadata(false));

public bool? ReturnedValue
{
 get { return (bool?)GetValue(ReturnedValueProperty); }
 set { SetValue(ReturnedValueProperty, value); }
}

The last nullable boolean type dependency property is the DefaultValue.

public static readonly DependencyProperty DefaultValueProperty =
 DependencyProperty.Register("DefaultValue", typeof(Boolean?), typeof(BoolComboBox),
 new PropertyMetadata(null, OnDefaultValuePropertyChanged));

private static void OnDefaultValuePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
 BoolComboBox boolComboBox = source as BoolComboBox;
 if (e.NewValue != null)
 {
  foreach (var p in boolComboBox.BindItems)
  {
   if (p.Value == (bool)e.NewValue)
   {
    boolComboBox.Text = p.Key;
    break;
   }
  }
 }
}

public bool? DefaultValue
{
 get { return (bool?)GetValue(DefaultValueProperty); }
 set { SetValue(DefaultValueProperty, value); }
}
At last we need to add an Event method so the ReturnedValue property is updated when user selected an option.
void BoolComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
 this.ReturnedValue = this.BindItems[this.SelectedValue.ToString()];
}
And in the InitialseItems method add this
this.SelectionChanged += new SelectionChangedEventHandler(BoolComboBox_SelectionChanged);
We have finished the code for BoolComboBox. When we need to use it we just need to add a piece of XAML like this:

The word "view" in front of "BoolComboBox" is the namespace name of this type.

Click here to download the code files.

No comments:

Post a Comment