views:

4960

answers:

4

I have a binary field in my database that is hard to describe in a UI using a single "Is XXXX?"-type checkbox. I'd rather use a pair of radio buttons (e.g. "Do it the Foo way" and "Do it the Bar way"), but right now all the other fields on my form are data-bound to a business object. I'd like to data-bind the pair of radio buttons to the business object as well, but haven't come up with a good way to do it yet. I can bind one of the buttons to the field, such that the field is set "true" if the button is selected, but while selecting the other button does de-select the first one (that is, the two radio buttons are properly paired), the value of the field does not update to reflect this.

I'd like to be able to say

button1.DataBindings.Add(new Binding("checked", source, "useFoo"));
button2.DataBindings.Add(new Binding("checked", source, "!useFoo"));

but I'm pretty sure that will throw when it runs. Is there an easier way, or should I just put more thought into how to word a single checkbox? I don't want to add extra functions to handle something this trivial...

ETA: A commenter has suggested considering a dropdown (ComboBox). I had thought about this, but how would I data-bind that to a boolean field in a database/Property in a business object? If I bind the SelectedItem to the useFoo property, what would go in the Items collection? Would I have to add just "True" and "False", or could I somehow add a key/value pair object that ties a displayed item ("Use Foo" / "Do Not Use Foo") to the boolean value behind it? I'm having trouble finding docs on this.


About the answer: the solution I wound up using involved modifying the business object -- the basic idea is very similar to the one posted by Gurge, but I came up with it separately before I read his response. In sort, I added a separate property that simply returns !useFoo. One radio button is bound to source.UseFoo, and the other is bound to source.UseBar (the name of the new property). It's important to make sure the new property has both getters and setters, or you'll wind up with really odd behavior.

A: 

You should only have to bind one of the controls as long as you make sure they are in the same group.

You could also consider a DropDown.

thealliedhacker
Try this: make a pair of radio buttons and a checkbox, and bind one radio button and the checkbox to the same boolean property under a bindingsource. Check the checkbox and toggle the radios -- nothing happens. Now, if you *un*check the checkbox, then toggle, you can turn it on, but never off.
Coderer
+1  A: 

I have found a way of doing this using DataSet/DataTable.

I make a calculated column in the DataTable with the expression IIF(Foo=true, false, true). Let's call that column Bar.

Bar is of type Boolean. Now you can bind one radiobutton.checked to Foo and one to Bar.

To get Bar checking/unchecking to propagate back to Foo you must go to the generated DataTable code and add one line, the last one in this sample:

            [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public bool Bar {
            get {
                try {
                    return ((bool)(this[this.tableradio.BarColumn]));
                }
                catch (global::System.InvalidCastException e) {
                    throw new global::System.Data.StrongTypingException("The value for column \'Bar\' in table \'radio\' is DBNull.", e);
                }
            }
            set {
                this[this.tableradio.BarColumn] = value;
                this[this.tableradio.FooColumn] = !value;
            }
        }
Guge
And don't forget to make this change again every time you edit your DataSet ! :-(
Mac
+1  A: 

if your business object Implements INotifyPropertyChanged (which makes binding work nicer)

you can add the following code to the visual interface where BO is your business object and is declared withevents and BO.Value is the boolean property you would like to bind to

Public Property NotValue() As Boolean
    Get
        Return Not BO.Value
    End Get
    Set(ByVal value As Boolean)
        BO.Value = Not value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
    End Set
End Property
Private Sub BO_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles BO.PropertyChanged
    If e.PropertyName = "Value" Then
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
    End If
End Sub

and the following bindings will hook up the Radio Buttons

    RBTrue.DataBindings.Add(New Binding("Checked", Me.BO, "Value", False, DataSourceUpdateMode.OnPropertyChanged))
    RBFalse.DataBindings.Add(New Binding("Checked", Me, "NotValue", False, DataSourceUpdateMode.OnPropertyChanged))

the visual interface should also implement INotifyPropertyChanged, this method works both ways the original value gets updated if the interface changes and if the original value changes the interface will update correctly.

+3  A: 
  1. Bind the RadioButton that is directly linked to your boolean value (ie is checked when the value is true).
  2. Add an event handler to the CheckedChanged event on this RadioButton that looks like the following :

    private void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        foreach (Binding b in ((Control)sender).DataBindings)
            b.WriteValue();
    }
    
Mac