-1

I have a radio button Boolean to integer converter class:

public class RadioBoolToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                          CultureInfo culture)
    {
        int integer = (int)value;
        if (integer == int.Parse(parameter.ToString()))
            return true;
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                              CultureInfo culture)
    {            
        return parameter;
    }
}

I have two radio buttons inside a stackpanel bound to a property "TestTypeRef":

<StackPanel Orientation="Horizontal">
    <RadioButton 
        Content="Screening" 
        Margin="0 0 10 0" 
        IsChecked="{Binding Path=TestTypeRef, Mode=TwoWay, Converter={StaticResource RadioBoolToIntConverter}, ConverterParameter=0 }" />
    <RadioButton 
        Content="Full" 
        Margin="0 0 10 0" 
        IsChecked="{Binding Path=TestTypeRef, Mode=TwoWay, Converter={StaticResource RadioBoolToIntConverter}, ConverterParameter=1 }" />
</StackPanel>

The problem arises when I try to set the value of the property to which the radiobuttons are bound, in the associated ViewModel.

When I set the value from 0 to 1 - this is fine.

When I set the value from 1 to 0 - the property value remains 1:

Inside the ViewModel:

// Set the default test type.
TestTypeRef = 0;
// ~~> TestTypeRef = 0
TestTypeRef = 1;  
// ~~> TestTypeRef = 1          
TestTypeRef = 0;
// ~~> TestTypeRef = 1 i.e. no change.

Many thanks for any help you can offer.

Update: Thank you to both @Rachel and @Will for their feedback. The ConvertBack routine was in error. This fixed it:

    return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;
AndyS
  • 53
  • 6
  • In your `ConvertBack` method of the converter always returns the value of the `ConverterParameter`, so it's always going to be 0 or 1, depending on what you set it to in the UI. That seems wrong, and smells like it has something to do with what you're observing. You should implement the ConvertBack method correctly, or see what's going on in there when you round-trip to the UI. –  Apr 06 '17 at 16:13
  • Hi @Will. Yep - error in the ConvertBack method. Thanks for your comment. – AndyS Apr 07 '17 at 07:45

2 Answers2

1

I think you may be using a converter incorrectly, but I'm not sure I understand your original premise.

A converter is used to convert a bound value to a different type. So what your converter is saying when it is reading the property from the UI for IsChecked, is

"compare bound value (TestTypeRef) to the parameter given. If the same, check the radio button"

It is also saying that when doing the reverse conversion (writing the IsChecked value back to the bound value (TestTypeRef), just

"send back the parameter value"

So to do the logic...

When the UI binds the values to read the IsChecked property

If TestTypeRef is equal to 0

    Radio 0 is checked because the value equals the parameter (0)
    Radio 1  is unchecked because the value does not equal the parameter (1)

If TestTypeRef is equal to 1

    Radio 0 is unchecked because the value does not equals the parameter (0)
    Radio 1  is checked because the value equals the parameter (1)

Now the problem comes in for your reverse binding, when it writes a value back to the data source

If Radio 0 is checked, write 0 to the datasource
If Radio 0 is unchecked, write 0 to the datasource
If Radio 1 is checked, write 1 to the datasource
If Radio 1 is unchecked, write 1 to the datasource

When you set the datasource value to something, it is triggering an update to the IsChecked value, which in turn writes back to the DataSource

Default : TestTypeRef = 0
    Radio 0 is checked
    Radio 1 is unchecked

Set TestTypeRef = 1
    Update Radio 0 Binding (Checked > Unchecked)
    Update Radio 1 Binding (Unchecked > Checked)

Because the IsChecked updates, it uses ConvertBack to update the data source. 
    If Radio 1 is checked, write 1 to the datasource

Note that at this point, the change event for Radio0 binding doesn't run, probably because it sees now that nothing has changed - Change event was raised, but value went from 1 to 1, so it doesn't run code to update anything.

You can confirm this by putting a breakpoint in your ConvertBack method, and you'll note it gets hit with a value of "1" when you try to set the value to 0. Another breakpoint in the setter of TestTypeRef will also show it changing the value first to 0, then back to 1 again.

Long story short, fix your converter. Or better yet, fix your design.

From what I can tell, you are trying to say "if bound value is equal to some value, isChecked is true", but from that statement you cannot get the reverse accurately. If user checks radio button, great you set bound value equal to parameter. If user unchecks radio button, it has no idea what to set the bound value to.

So either

  1. Change your bindings to OneWay so they never run ConvertBack and update the data source. Not ideal if you want users to actually use the radio buttons.
  2. Change your bound value so it's formatted in a correct way to display data, such as two bool properties called IsFull and IsScreening that you can bind directly
  3. Implement a better set of UI controls for this. My personal preference is a ListBox bound to a single value and styled with RadioButtons, but that might be overkill for what is essentially a bool value.

Personally I would go suggest 2 for you right now.

public bool IsScreening
{ 
    get { return TestTypeRef == 0; }
    set { if (value) TestTypeRef = 0; }
}

public bool IsFull
{ 
    get { return TestTypeRef == 1; }
    set { if (value) TestTypeRef = 1; }
}
Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Thank you, @Rachel, for an excellent walk-through. The ConvertBack routine was in error. This fixed it: return value.Equals(false) ? DependencyProperty.UnsetValue : parameter; – AndyS Apr 07 '17 at 07:48
0

We will need to use a converter parameter to specify which value a radio button corresponds to. If your property equals this value then this button will be checked and other buttons unchecked. This solution works regardless whether you set the GroupName property or not, though you should normally set it.

you can see the solution

Sivamohan Reddy
  • 436
  • 1
  • 8
  • 26