WPF coding mutually exclusive Check Boxes with Data Binding

, ,

Last week I was coding a View that required for me to show two ChekBox controls which were mutually exclusive in the same way that two or more RadioButton controls that belong to the same group would interact.

My problem was that one Boolean property which came from a bit column in the database needed to drive which CheckBox would be checked: “Yes” or “No”.

In this example I attempt to show how to code two mutually exclusive checkboxes while binding to the Boolean property described above:

image

The Name of the Property in the Code Behind file that we are going to bind to is AddInsurance.

Here is the XAML code:

<Window x:Class="HellsKitchen.MainWindow2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:conv="clr-namespace:HellsKitchen"
    Height="123"
    Width="324"
    Title="{Binding WindowTitle}"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <Window.Resources>
        <ResourceDictionary>
            <conv:InverseBooleanConverter x:Key="InvBooleanConverter" />
        </ResourceDictionary>
    </Window.Resources>

    <StackPanel Orientation="Horizontal" Height="24" Width="259">

        <Label Name="lblPreRecordingState" Content="Add Insurance :"
            Width="102" HorizontalAlignment="Stretch"
               HorizontalContentAlignment="Left"/>

        <CheckBox Name="chkPRSYes"  Content="Yes"
                  Margin="3,2,0,0" Height="16"
                  IsChecked="{Binding AddInsurance}"
                />

        <CheckBox Name="chkPRSENo"  Content="No"
                  Margin="15,2,0,0" Height="16"
                  IsChecked="{Binding Path=IsChecked,
                             ElementName=chkPRSYes,
                             Converter={StaticResource InvBooleanConverter}}"
                />
        <Button Content="Button" Height="23" Name="button1"
                Width="75" Margin="5,0,0,0" Click="button1_Click" />
    </StackPanel>
</Window>

Here is the Code Behind C#:

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;

namespace HellsKitchen
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow2 : Window
  {
    // Dependency Property
    public string WindowTitle
    {
      get { return (string)GetValue(_WindowTitle); }
      set { SetValue(_WindowTitle, value); }
    }
    // declare a dependency property that will
    // allow us to bind to our code behind
    // Not really sure why this works yet, but it does.
    // we declare the dependency property here
    // and set its : name, type, owner, default value
    public static readonly DependencyProperty _WindowTitle =
    DependencyProperty.Register("WindowTitle", typeof(string),
                       typeof(MainWindow2),
                       new FrameworkPropertyMetadata("Exclusive CheckBoxes"));

    private bool addInsurance;
    public bool AddInsurance
    {
      get
      {
        return this.addInsurance;
      }
      set
      {
        this.addInsurance = value;
      }
    }
    public MainWindow2()
    {
      InitializeComponent();
    }
    private void button1_Click(object sender, RoutedEventArgs e)
    {
      Debug.Print("The value of addInsurance is: " +
                  this.addInsurance.ToString());
    }
  }
  public class InverseBooleanConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter,
    System.Globalization.CultureInfo culture)
    {
      if (value == null)
        return false;
      return !(bool)value;
    }
    public object ConvertBack(object value, Type targetType, object parameter,
    System.Globalization.CultureInfo culture)
    {
      if (value == null)
        return false;
      return !(bool)value;
    }
  }
}

Let’s take a look at important areas in the code:

  1. We Set the DataContext for the Window to itself: DataContext=”{Binding RelativeSource={RelativeSource Self}}”>
  2. We create a dependency property in code behind and bind the Window’s Title property to it. For some reason, doing steps 1 and 2 allow us to bind to any other public member in the code behind. Once I find out why this is, I will let you know: Title=”{Binding WindowTitle}”
  3. In the XAML we add a Window Resource which points to the InverseBooleanConverter class in code behind.
  4. The wiring for the code behind converter to the xaml page is done by adding the line of code towards the top of the xaml page that reads like this: xmlns:conv=”clr-namespace:HellsKitchen”
  5. We now spin up a CheckBox control (the yes check box) and add a Binding to it’s IsChecked property  to the value AddInsurance property of the code behind.
  6. We spin up a second CheckBox control and add a Binding to it’s IsChecked property to the value of the IsChecked property of the FRIST checkbox by way of the InverseBooleanConverter which should return the opposite of any Boolean value we give it.

We can check the value of AddInsurance by clicking the Button, which will display to the Output window the current value of the AddInsurance variable. The value printed should match and coincide with the checked box on the window.

The solution above helped me meet my requirement while staying away from putting unnecessary business logic in my code behind such as adding Checked Events for each of the CheckBoxes, etc. The solution is also clean because we are advantage of XAML’s declarative nature. Hope this helps and let me know if you have any questions.

Sun


5 responses to “WPF coding mutually exclusive Check Boxes with Data Binding”

  1. One of my co workers mentioned that for a single boolean (bit) type only ONE check box should be used. I agree with that, but in my case there were two other factors:

    1. One of the check box pairs was UPS or Courier, I had to use two.
    2. The other couple of instances were coded as such because that was the requirement. 🙂

  2. An outstanding share! I have just forwarded this onto a coworker who was conducting
    a little homework on this. And he in fact bought me lunch because I discovered it
    for him… lol. So allow me to reword this…. Thanks for the
    meal!! But yeah, thanx for spending some time to talk about this issue here
    on your blog.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.