Monday, 5 December 2011

RadioButton groups

A workaround from Martin for RadioButton groups.

There’s a bug in WPF (still) around RadioButton groups which doesn’t immediately manifest but will eventually seem to strike.

There’s a slightly confusing summary of issues here : http://social.msdn.microsoft.com/forums/en-US/wpf/thread/8eb8280a-19c4-4502-8260-f74633a9e2f2/

Suffice to say if you have 2 (or more) radio buttons and put them in the same group, they will reliably update each others status for a while as you’d expect. At some point (in my case I found this reliably happens after changing Document tabs a few times, or going forwards & back again in a Wizard workflow), the bindings stop working and you end up unable to check either RadioButton anymore.

I’ve messed around with various approaches – a couple are suggested in the post above.
The simplest option appears however to simply drop the GroupName=”x” from the XAML and simply do the “single-selection” logic yourself in the backing properties on your VM.

i.e. :
<RadioButton ssform:FormItem.LabelContent="{Binding Source={StaticResource ViewModel}, Path=Strings.V_Coupon, Mode=OneTime}"
                            Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_eCoupon, Mode=OneTime}"
                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"
                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsECouponATrigger, Mode=TwoWay}" />
<RadioButton Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_PrintCoupon, Mode=OneTime}"
                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"
                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsPrintedCouponATrigger, Mode=TwoWay}" />

and
public bool IsPrintedCouponATrigger
{
   get { return PromoBase.UIChoices.IsPrintedCouponATrigger; }
   set
   {
      if (value != PromoBase.UIChoices.IsPrintedCouponATrigger)
      {
         PromoBase.UIChoices.IsPrintedCouponATrigger = value;
         IsECouponATrigger = !value;
         OnPropertyChanged("IsPrintedCouponATrigger");
      }
   }
}
public bool IsECouponATrigger
{
   get { return PromoBase.UIChoices.IsECouponATrigger; }
   set
   {
      if (value != PromoBase.UIChoices.IsECouponATrigger)
      {
         PromoBase.UIChoices.IsECouponATrigger = value;
         IsPrintedCouponATrigger = !value;
         OnPropertyChanged("IsECouponATrigger");
      }
   }
}
Note the check that the value has actually changed in the setter – without this, you get into a nice infinite loop of PropertyChange notifications as each changes the other in turn!

Annoying bug, but simple enough to work around once you know about it..

No comments: