.NET Framework Developer Center > .NET Development Forums > Windows Presentation Foundation (WPF) > RadioButton unchecked bindings issue still not resolved?
Ask a questionAsk a question
 

AnswerRadioButton unchecked bindings issue still not resolved?

  • Friday, August 24, 2007 8:16 PMNoSuch Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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!

Answers

  • Friday, August 24, 2007 8:37 PMNoSuch Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    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.
  • Saturday, August 25, 2007 12:35 AMSam Bent - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    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.

     

     

All Replies

  • Friday, August 24, 2007 8:37 PMNoSuch Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    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.
  • Saturday, August 25, 2007 12:35 AMSam Bent - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    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.

     

     

  • Sunday, August 26, 2007 6:09 AMNothingButNet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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 2:01 PMNoSuch Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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!

  • Monday, August 27, 2007 9:02 PMSam Bent - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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 10:17 PMNothingButNet Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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.

  • Tuesday, December 04, 2007 9:28 PMDave Gallagher Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    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".

  • Monday, June 02, 2008 8:56 PMkarliwatson Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    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> 

  • Friday, September 05, 2008 2:14 PMBruno Martinez Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Proposed AnswerHas Code
    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" /> 
    • Proposed As Answer bypooranlive Tuesday, October 20, 2009 5:11 AM
    • Edited byBruno Martinez Friday, September 05, 2008 2:18 PMFormatting
    •  
  • Monday, September 15, 2008 10:02 AMArneWauters Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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

  • Monday, September 15, 2008 4:40 PMDave Gallagher Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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>

  • Tuesday, October 21, 2008 5:45 PMpasx2578 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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


  • Wednesday, October 22, 2008 8:27 AMpasx2578 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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
  • Tuesday, March 03, 2009 5:06 PMDavid McMullen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks for the tip.  I process each of two RadioButtons separately so putting them in separate groups is exactly what I needed to do.
  • Monday, March 09, 2009 8:23 PMRaidah Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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, July 06, 2009 5:00 PMSam Bent - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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
  • Wednesday, July 08, 2009 12:28 AMNoSuch Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    That is awesome news - thanks Sam!
  • Tuesday, October 20, 2009 10:03 AMArneWauters Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    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.