none
RadioButton unchecked bindings issue still not resolved?

    Question

  • I recently noticed that when I bind a RadioButton to a bool, that bool is set when the RadioButton is checked but never unset when it's unchecked.  After reading the following post:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1429712&SiteID=1

    I noticed that furthermore the bindings are totally dropped after a few clicks between two RadioButtons.  Surely this is a bug, does anyone have an update on it's status?  Binding to RadioButtons is such a common thing that I'd have to image it's been addressed by now.

    Thanks!
    Friday, August 24, 2007 8:16 PM

Answers

  • I can further confirm that the bindings are lost by attempting to do things with UpdateSourceTrigger=Explicit and handling the checked and unchecked events.  When the RadioButton is checked for the first time I can get a BindingExpression for RadioButton.IsCheckedProperty and call UpdateSource.  However, when I pick a different RadioButton and the uncheck event fires I try to do the same thing and the BindingExpression for RadioButton.IsCheckedProperty is gone.  I can't find a workaround other than to forgo data binding with RadioButtons.
    Friday, August 24, 2007 8:37 PM
  • This is a known bug, with no known workaround.

     

    Sadly, the situation is more complex than you might think.  When you click one button, the other buttons in the group are supposed to clear.  How can RadioButton do this?  If it calls SetValue(IsClicked, false), it sets a local value and hides the value provided by a style or template.  If it calls ClearValue(IsClicked) it removes the binding.  The first approach breaks one set of apps, the second breaks a different set of apps.  Someone is always unhappy.

     

     

    Saturday, August 25, 2007 12:35 AM

All replies

  • I can further confirm that the bindings are lost by attempting to do things with UpdateSourceTrigger=Explicit and handling the checked and unchecked events.  When the RadioButton is checked for the first time I can get a BindingExpression for RadioButton.IsCheckedProperty and call UpdateSource.  However, when I pick a different RadioButton and the uncheck event fires I try to do the same thing and the BindingExpression for RadioButton.IsCheckedProperty is gone.  I can't find a workaround other than to forgo data binding with RadioButtons.
    Friday, August 24, 2007 8:37 PM
  • This is a known bug, with no known workaround.

     

    Sadly, the situation is more complex than you might think.  When you click one button, the other buttons in the group are supposed to clear.  How can RadioButton do this?  If it calls SetValue(IsClicked, false), it sets a local value and hides the value provided by a style or template.  If it calls ClearValue(IsClicked) it removes the binding.  The first approach breaks one set of apps, the second breaks a different set of apps.  Someone is always unhappy.

     

     

    Saturday, August 25, 2007 12:35 AM
  • IMO the issue would best be resolved by having a group of radio buttons behave in the way most people would assume they do.

    To be more explicit - if you have TwoWay bindings on a group of RadioButtons they would remain in place as long as the RadioButtons were in existance. When the value of IsChecked changes for any RadioButton the associated binding would record the change.

    In my own coding I cannot think of a scenario where I would want WPF to remove a RadioButton binding automatically.  I think Styles/Templates that are "looking at" IsChecked would be referencing it via a comparison in a Trigger or if the developer is explicitly setting it then he's unlikely to be binding it to it ALSO.

    Said differently, if you code up an application where you trample on your own bindings via a Style or Template, then that's either your error or intention.

    I'm not sure what I'm missing but this issue seems simple to me.

    If the RadioButton has a binding expression, I don't think WPF should remove it period.

    I find the current behavior makes a RadioButton group much harder to use than necessary. I'm forced to listen to a Click event on each button and do the "right" thing.

    Can this issue be addressed in the .NET 3.5 release?

    Would you mind providing examples to better illustrate the complexity you refer to? I understand how using ClearValue instead SetValue would cause the problem described in this thread, but I can't think of a case where ClearValue should be called automatically. Please elaborate.

    Thanks.




    Sunday, August 26, 2007 6:09 AM
  • I completely agree with Richie and would also like to see an example illustrating the complexity Sam mentioned.  I'm planning to handle binding to the radio button manually through listening to Checked / Unchecked but I also plan to have a trigger listening for the Checked value to change that would cause some data styling.  Thanks for setting things straight Sam!

    Sunday, August 26, 2007 2:01 PM
  • When you click a RadioButton, the internal code has to do something to clear the other buttons in the group.  Once upon a time it used to call SetValue(false), but someone complained because their app relied on values and triggers defined in a style - setting a local value hid this completely.  So it got "fixed" by calling ClearValue instead.  This broke apps like yours that use data binding on IsChecked.  No one realized this until fairly recently. 

     

    I totally agree that the internal code should not trample your bindings.  The "fix" we shipped needs to be improved to take this case into account.  It's probably too late for WPF 3.5, but this should certainly be addressed for the next release after that.

    Monday, August 27, 2007 9:02 PM
  • Hi Sam,

     

    Thanks for clarifying how the situation came to be the way it is. It's great to hear you guys want to improve the "fix".

     

    If it can't make it into 3.5, hopefully that means RTM is just around the corner Smile

     

    Thanks.

    Monday, August 27, 2007 10:17 PM
  • I've resorted to defining a PageLoaded method that caches the Binding objects of each RadioButton in Page.Resources. Then I have a handler for the Unchecked event, which checks the status of the bindings and restores them if necessary. Not what I really want to be doing, but it "works".

    Tuesday, December 04, 2007 9:28 PM
  • I ran into this one today and have an alternative solution that you can use in certain circumstances.

    If your radio buttons are in a list, horizontal or vertical, you can use a ListBox with a style that maps the IsSelected property of a ListBoxItem to the IsChecked property of its items.

    In my tests this appears to preserve the bindings you use and everything works as expected. I've included code below for a vertical list box style and test list in case you decide to go with this strategy!

        <Style x:Key="VerticalRadioButtonListStyle" TargetType="ListBox"
            <Style.Resources> 
                <Style TargetType="ListBoxItem"
                    <Setter Property="Template"
                        <Setter.Value> 
                            <ControlTemplate TargetType="ListBoxItem"
                                <Grid Margin="2"
                                    <Grid.ColumnDefinitions> 
                                        <ColumnDefinition Width="Auto" /> 
                                        <ColumnDefinition /> 
                                    </Grid.ColumnDefinitions> 
                                    <RadioButton IsChecked="{Binding IsSelected, 
                                        RelativeSource={RelativeSource TemplatedParent}, 
                                        Mode=TwoWay}" /> 
                                    <ContentPresenter Grid.Column="1" Margin="2,0,0,0" /> 
                                </Grid> 
                            </ControlTemplate> 
                        </Setter.Value> 
                    </Setter> 
                </Style> 
            </Style.Resources> 
            <Setter Property="ItemsPanel"
                <Setter.Value> 
                    <ItemsPanelTemplate> 
                        <WrapPanel Orientation="Vertical"  /> 
                    </ItemsPanelTemplate> 
                </Setter.Value> 
            </Setter> 
            <Setter Property="BorderThickness" Value="0" /> 
            <Setter Property="Background" Value="Transparent" /> 
        </Style> 


    ...

            <ListBox Name="ReportingLevelRadioButtonList" Style="{StaticResource VerticalRadioButtonListStyle}" Grid.Column="1"
                <ListBox.Items> 
                    <ListBoxItem IsSelected="{Binding ...}">Option 1</ListBoxItem> 
                    <ListBoxItem IsSelected="{Binding ...}">Option 2</ListBoxItem> 
                    <ListBoxItem IsSelected="{Binding ...}">Option 3</ListBoxItem> 
                </ListBox.Items> 
            </ListBox> 

    • Proposed as answer by Dan_27 Tuesday, June 21, 2011 6:55 PM
    Monday, June 02, 2008 8:56 PM
  • I've been able to workaround this issue by explicitly putting my RadioButtons in separate groups:
    <RadioButton     
        GroupName="Apples"    
        IsChecked="{Binding Path=IsApples}"    
        Content="Apples" />    
    <RadioButton     
        GroupName="Oranges"    
        IsChecked="{Binding Path=IsOranges}"    
        Content="Oranges" /> 
    • Edited by Bruno Martinez Friday, September 05, 2008 2:18 PM Formatting
    • Proposed as answer by pooranlive Tuesday, October 20, 2009 5:11 AM
    Friday, September 05, 2008 2:14 PM
  • Why not bind to a bool like this?

    in the BO:

            private bool _MyBool;

            public bool MyBool
            {
                get { return _MyBool; }
                set { _MyBool = value; OnPropertyChanged("MyBool"); } //INotifyPropertyChanged Interface
            }

    Xaml:
       
        <RadioButton GroupName="someGroup" IsChecked="{Binding Path=MyBool, Converter={StaticResource ConvertToOppositeBool}}">False</RadioButton>

        <RadioButton GroupName="someGroup" IsChecked="{Binding Path=MyBool}">True</RadioButton>

    Does the trick for me.

    Greets,

    Arne

    • Edited by ArneWauters Monday, September 15, 2008 10:04 AM
    Monday, September 15, 2008 10:02 AM
  • I did try something similar to that as well, but the issue of the binding being suddenly dropped was still there. It looks like styling the button group as a ListBox is really the only way to go to avoid that for the moment.

    What can also be very useful is to have the buttons in the group bound to an integer dependency, rather than a boolean. The following code is similar to what I used (similar to karliwatson's):

    <Style x:Key="RadioButtonGroupStyle" TargetType="{x:Type ListBox}">
      <
    Setter Property="HorizontalAlignment" Value
    ="Left"/>
      <
    Setter Property="VerticalAlignment" Value
    ="Center"/>
      <
    Setter Property="BorderBrush" Value
    ="Transparent"/>
      <
    Setter Property="KeyboardNavigation.DirectionalNavigation" Value
    ="Cycle"/>
      <
    Setter Property
    ="ItemContainerStyle">
        <
    Setter.Value
    >
          <
    Style TargetType="{x:Type ListBoxItem
    }" >
            <
    Setter Property="Margin" Value
    ="2, 2, 2, 0" />
            <
    Setter Property
    ="Template">
              <
    Setter.Value
    >
                <
    ControlTemplate TargetType="{x:Type ListBoxItem
    }">
                  <
    Border Background
    ="Transparent">
                    <
    RadioButton IsHitTestVisible="False" Focusable="False" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"  Content="{TemplateBinding Content
    }"/>
                 </
    Border
    >
               </
    ControlTemplate
    >
             </
    Setter.Value
    >
           </
    Setter
    >
          </
    Style
    >
        </
    Setter.Value
    >
      </
    Setter
    >
    </
    Style
    >

    ...


    <GroupBox>
      <
    ListBox Name="MySelector" Style="{StaticResource RadioButtonGroupStyle}" Grid.Row
    ="0">
        <
    ListBox.Items
    >
          <
    ListBoxItem Name="Item0" >Option 0</ListBoxItem
    >
          <
    ListBoxItem Name="Item1">Option 1</ListBoxItem
    >
          <
    ListBoxItem Name="Item2">Option 2</ListBoxItem
    >
        </
    ListBox.Items
    >
        <
    ListBox.SelectedIndex
    >
          <
    Binding Path="MyIntProperty" Mode="TwoWay" UpdateSourceTrigger
    ="PropertyChanged"/>
        </
    ListBox.SelectedIndex
    >
      </
    ListBox
    >
    </
    GroupBox>


    alternatively, you could use ItemsSource bound to an enum (optionally filtered via a System.Windows.Data.CollectionViewSource):

    <GroupBox>
      <
    ListBox Name="MySelector" Style="{StaticResource RadioButtonGroupStyle}" ItemsSource="{Binding Source={StaticResource MyFilteredCollectionViewSource
    }}">
        <
    ListBox.SelectedItem
    >
          <
    Binding Source="{StaticResource mydata}" Path="MyEnumProperty" Mode="TwoWay" UpdateSourceTrigger
    ="PropertyChanged"/>
        </
    ListBox.SelectedItem
    >
      </
    ListBox
    >
    </
    GroupBox>

    Monday, September 15, 2008 4:40 PM
  • I hit that problem too and found it a real nuisance.
    I tried to get rid of the GroupName as some post suggested to no avail.
    I tried to force an update of the binding by code but I hit an exception as I guess the framework removes the binding so the BindingExpression becomes null...
    I finally used the Checked event on each radio to call a generic update routine:

            private void myRadio_Checked(object sender, RoutedEventArgs e)
            {
                updateRadio(sender);
            }

            void updateRadio(object sender)
            {
                //find the radio
                RadioButton rd= (RadioButton)sender;
        //I used the Tag property of the radio to store the name of the property I want to update
                string s = rd.Tag.ToString();
                //retrieve the object containing the properties to update
                WizardData data = (WizardData)this.DataContext;
                //call a generic invoke function to set the properties
                InvokeTypeMember<WizardData>(data, s, new object[1] { true } );
            }

    using System.Reflection;
    //InvokeMember allows you to set a property once you know its name
            public static void InvokeTypeMember<T>(object obj, string prop, object[] arg)
            {
                Type myType = obj.GetType();
                myType.InvokeMember(prop, BindingFlags.SetProperty, null, obj, arg);
            }

    I always set the value to true once the radio is clicked.
    In the WizardData object where my properties live, I have an extra function to set all the properties to false which is called by each property related to the radio on the set:

            void clearProps()
            {
                WizardSettings.Default.page4_Option1 = false;
                WizardSettings.Default.page4_Option2 = false;
                ...
            }

            public bool Option1
            {
                get { return WizardSettings.Default.page4_Option1; }
                set { clearProps();  WizardSettings.Default.page4_Option1 = value; }

    The only thing I got left to do at this point is to check that at least one property is true when loading the page and set the UI accordingly.
    This will be done using the property returned by
    object val = (object)myType.InvokeMember(prop, BindingFlags.GetProperty, null, obj, null);
    which will be called repetitively for all the radios to check if val is true.

    Still this is a lot of code to work around the bug or... have I got something wrong in the first place and can this be simplified?

    Thanks
    Pasx


    Tuesday, October 21, 2008 5:45 PM
  • In addition to my post above.
    I finally found it easier to rely on a one way binding to update the relation b/w the source properties and the radio buttons.
    The binding works fine this way so on loading the page the appropriate radio button is checked without additional code behind.

    the xaml now looks like:

        <RadioButton Name="rdOption1" Tag="page4_Option1"
    IsChecked="{Binding Path=page4_Option1, Mode=OneWay}"
    Checked="myRadio_Checked">Option1</RadioButton>

    Pasx
    Wednesday, October 22, 2008 8:27 AM
  • Thanks for the tip.  I process each of two RadioButtons separately so putting them in separate groups is exactly what I needed to do.
    Tuesday, March 03, 2009 5:06 PM
  • I have the same problem and I tried the ListBox styling work-around

    The problem is that when compiled in VS the xaml shows an error with setting the Content property

                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                  <
    Border Background
    ="Transparent">
                    <
    RadioButton IsHitTestVisible="False" Focusable="False" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"  Content="{TemplateBinding Content
    }"/>
                 </
    Border
    >
               </
    ControlTemplate
    >

    When I remove the Content property things work fine (including events and binding), but there is no text next to the radio button.

    I tried changing the code to:

                                    <ControlTemplate>
                                        <Border Background="Transparent">
                                            <StackPanel Orientation="Horizontal">
                                                <ContentControl Content="{TemplateBinding Content}"/>
                                                <RadioButton IsHitTestVisible="False" Focusable="False" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
                                            </StackPanel>
                                        </Border>
                                    </ControlTemplate>

    This code has a compile error "Cannot find the static member 'ContentProperty' on the type 'Control'"

    I'm using .NET 3.5 sp1 and RadioButton binding still doesn't work



    Sten
    Monday, March 09, 2009 8:23 PM
  • The original problem has been fixed for WPF 4.0.    I'm still not aware of a completely satisfactory workaround in 3.x.
    Dev Lead, Windows Presentation Foundation, WinFX
    Monday, July 06, 2009 5:00 PM
  • That is awesome news - thanks Sam!
    Wednesday, July 08, 2009 12:28 AM
  • I've found that this solutions works like a charm: http://pstaev.blogspot.com/2008/10/binding-ischecked-property-of.html . Thanks to Peter Staev.
    Tuesday, October 20, 2009 10:03 AM
  • I have found a solution accidentally! :) I had the same problem when using two radio buttons and the solution was to use BindingGroupName when binding the IsChecked property. Here is an example:
    <RadioButton Grid.Row="1" GroupName="AlarmSound1" Command="{Binding SelectDefaultAlarmSoundCommand}" Content="Default alarm sound" IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=IsDefaultAlarmSoundSelected, Mode=TwoWay, BindingGroupName=AlarmSound}" />
    <RadioButton Grid.Row="2" GroupName="AlarmSound2" Command="{Binding SelectCustomAlarmSoundCommand}" Content="Custom alarm sound" VerticalAlignment="Center" IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=IsCustomAlarmSoundSelected, Mode=TwoWay, BindingGroupName=AlarmSound}" />
    Notice how the GroupName properties are different and BindingGroupName is the same!
    Now when I call Settings.Default.Reset() it properly restores the IsCheked property of those two radio buttons.

    Cheers
    • Proposed as answer by Jenkis Wednesday, July 06, 2011 4:56 AM
    • Unproposed as answer by Jenkis Wednesday, July 06, 2011 5:24 AM
    Friday, December 11, 2009 8:25 AM
  • <ListBox>
    <RadioButton   
      GroupName="Apples"   
      IsChecked="{Binding Path=FRUITS}"   
      Content="Apples" />   
    <RadioButton   
      GroupName="Oranges"   
      IsChecked="{Binding Path=FRUITS}"   
      Content="Oranges" /> 
    
    </ListBox>

    Nice tip Bruno. But, I have a situation where I have these radio buttons in a listbox. Something like above(observe that both radio buttons are bound to same column). My list box is bound to a child table. Now, when I add multiple items to the child table (for the same pri key of parent). If I select "Apples" in the first row and "Apples" for the second row, then "Apples" for the first row is being unchecked.

     


    Raghu
    Thursday, July 01, 2010 11:32 AM
  • Even with .NET 4.0SP1 I still needed to use karliwatson's solution.  These bugs in the RadioButton may have been reduced with 4.0, but they all have not been fixed!  

    The bugs worsen if you use RadioButton in a UserControl, and then create more than one instance of the Control.  Bindings get mysteriously dropped, and the RadioButtons come "unchecked" for no apparent reason when switching between UserControl instances.

     

    Thanks so much for the listbox idea! This  has fixed my application.    For those of you wanting their checkboxes to be horizontal, just add this:

    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"/>
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>

     

    Dan

    Tuesday, June 21, 2011 7:01 PM
  • My problem was that I had 4 radiobuttons, all with different groupname settings, each radiobutton's IsChecked is bound to a different bool on my class.  When the user navigated (using the WPF navigation framework) to a different page, then navigated back, the radiobuttons had lost their value.

    I put a breakpoint in the bool property to which the radiobutton is bound, and found that right when I called  NavigationFrame.Navigate(content). the bound property of the IsChecked=true radiobutton was being set to false.

     

    Now, this is a truly bizarre thing.  At first I had groupnames = single characters, and the above behaviour occurred.  For some reason, I changed the groupnames to longer words and the problem was fixed.  And no, before you ask, there are no other radiobuttons around the place with the original groupnames.

    FAILS :

    <RadioButton GroupName="D" Content="Unknown" IsChecked="{Binding IsUnknown}"/>
    
    <RadioButton GroupName="A" Content="Tank System" IsChecked="{Binding IsTankSystem}"/>
    
    <RadioButton GroupName="B" Content="Vehicle" IsThreeState="False" IsChecked="{Binding IsTrailer}" />
    
    <RadioButton GroupName="C" Content="Single Asset" IsThreeState="False" IsChecked="{Binding IsAsset}" />
    
    

    WORKS :

    <RadioButton GroupName="GroupD" Content="Unknown" IsChecked="{Binding IsUnknown}"/>
    
    <RadioButton GroupName="GroupA" Content="Tank System" IsChecked="{Binding IsTankSystem}"/>
    
    <RadioButton GroupName="GroupB" Content="Vehicle" IsThreeState="False" IsChecked="{Binding IsTrailer}" />
    
    <RadioButton GroupName="GroupC" Content="Single Asset" IsThreeState="False" IsChecked="{Binding IsAsset}" />
    

     

    Radiobutton binding is truly a mess.


    Wednesday, July 06, 2011 4:56 AM
  • I've been able to workaround this issue by explicitly putting my RadioButtons in separate groups:
    <RadioButton     
        GroupName="Apples"    
        IsChecked="{Binding Path=IsApples}"    
        Content="Apples" />    
    <RadioButton     
        GroupName="Oranges"    
        IsChecked="{Binding Path=IsOranges}"    
        Content="Oranges" /> 
    Tuesday, September 13, 2011 8:22 AM
  • I've been able to workaround this issue by explicitly putting my RadioButtons in separate groups:
    <RadioButton     
        GroupName="Apples"    
        IsChecked="{Binding Path=IsApples}"    
        Content="Apples" />    
    <RadioButton     
        GroupName="Oranges"    
        IsChecked="{Binding Path=IsOranges}"    
        Content="Oranges" /> 
    Tuesday, September 13, 2011 8:23 AM
  • I've been able to workaround this issue by explicitly putting my RadioButtons in separate groups:
    <RadioButton     
        GroupName="Apples"    
        IsChecked="{Binding Path=IsApples}"    
        Content="Apples" />    
    <RadioButton     
        GroupName="Oranges"    
        IsChecked="{Binding Path=IsOranges}"    
        Content="Oranges" /> 
    Tuesday, September 13, 2011 8:26 AM
  • I've been able to workaround this issue by explicitly putting my RadioButtons in separate groups:
    <RadioButton     
        GroupName="Apples"    
        IsChecked="{Binding Path=IsApples}"    
        Content="Apples" />    
    <RadioButton     
        GroupName="Oranges"    
        IsChecked="{Binding Path=IsOranges}"    
        Content="Oranges" /> 
    Tuesday, September 13, 2011 9:14 AM
  • I just discovered a great solution to this problem.

    Assuming you have two radios that need to be able to be checked/unchecked, implement this code and change what's necesarry:


     var gift_click = 0;
              function HandleGiftClick() {
                  if (document.getElementById('LeftPanelContent_giftDeed2').checked == true) {
                      gift_click++;
                      memorial_click = 0;
                  }
                  if (gift_click % 2 == 0) {document.getElementById('LeftPanelContent_giftDeed2').checked = false; }
              }
              var memorial_click = 0;
              function HandleMemorialClick() {
                  
                  if (document.getElementById('LeftPanelContent_memorialDeed2').checked == true) {
                      memorial_click++;
                      gift_click = 0;
                  }
                  if (memorial_click % 2 == 0) { document.getElementById('LeftPanelContent_memorialDeed2').checked = false; }
              }

    :) your welcome
    Thursday, February 09, 2012 6:12 PM
  • Today,  I came across this problem when implementing the undo/redo for RedioButton group. I didn't change the codes in the xaml file, only added one sentence in my undorable class. Now my RedioButtton group works well.

     private class SelectionModeUndoable : AbstractUndoable
                {
                    private IPresenter presenter;
                    private SelectionOption? oldValue;
                    private SelectionOption? newValue;

                    public SelectionModeUndoable(IPresenter presenter, SelectionOption? oldValue, SelectionOption? newValue)
                    {
                        this.presenter = presenter;
                        this.oldValue = oldValue;
                        this.newValue = newValue;
                    }

                    public override void Undo()
                    {
                        this.presenter.SelectionMode = null;
                        this.presenter.SelectionMode = this.oldValue;
                    }

                    public override void Redo()
                    {
                        this.presenter.SelectionMode = null;
                        this.presenter.SelectionMode = this.newValue;
                    }
                }


    Tuesday, July 03, 2012 7:44 AM