Using ApplicationSettings to store Checked property for WinForms RadioButtons
Asked Answered
H

4

5

I have a WinForms dialog box that contains 3 radio buttons. I am using ApplicationSettings to bind the Checked property of each of these RadioButton controls, but it doesn't do what I am expecting it to do. Now I have to click each radio button twice before it gets checked and the selected radio button is not being persisted.

Is there a line of code I need to execute when the form is closed that saves the user settings?

How do I eliminate the need for 2x clicking on the radio buttons?

Is there a better way to persist this type of user setting? I do have a public property on the dialog box class that gets/sets an enum value based on which radio button is checked, but I didn't see an easy way of binding that property to a user setting.

Edit: Should have specified that I'm using vb.net. I think that means My.Settings instead of Properties.Settings.

Highcolored answered 1/6, 2009 at 23:21 Comment(0)
T
3

I can answer this part of your question:

Is there a line of code I need to execute when the form is closed that saves the user settings?

Application settings are stored in your Settings class, in the Properties namespace. The Settings class has a static property called Default, which represents the current settings for your application. So in your main form's Closing event, you call:

Properties.Settings.Default.Save();

... to save the settings.

Likewise you can get to the settings programatically using the setting's name: Properties.Settings.Default.MyRadioButtonState (or whatever you've called it).

Tadich answered 1/6, 2009 at 23:25 Comment(2)
Thanks! That got me going in the right direction. In vb.net it's My.Settings instead of Properties.Settings.Default, but other than that, it works perfectly. I now only have one setting and am using the form's public property in the Load and FormClosing events.Highcolored
On my computer it is not necessary to save the settings on closing. They are saved automatically. The only problem is that I have to click two times.Hols
H
6

I answer this part of your question:

How do I eliminate the need for 2x clicking on the radio buttons?

You can add the following event handler to the Click event of each of the three RadioButtons (of which the Checked properties are bound to Application Settings) in your GroupBox:

Private Sub RadioButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tomRadioButton.Click, dickRadioButton.Click, harryRadioButton.Click
    If sender.Checked = False Then
        sender.Checked = True
    End If
End Sub

It works, even though it takes a half-second for an unckecked RadioButton to be checked after you click it.

The reason for the problem was explained two years ago (in 2008) in section 5 of the Surviving WinForms Databinding post on the Turbulent Intelect blog (Thank you, ohadsc, for the link):

Rule 5: Don't bind to clickable Radio Buttons

I know how great it would be if you could just bind your bunch of radio buttons to an enum property. I really do. You think you're just going to hook up some Format and Parse events to translate back to your enum, and all will be well. It would be so darn convenient, if it actually worked. But WinForms just isn't cut out for this. For 3 full releases now (or is it 3.5 releases?), this has been the case. It's because of the event order, which is not something that MS can go switching up without causing thousands of developers to get really cheesed off.

The problem really comes down to the fact that unlike other controls' data properties, the Checked property of a radio button doesn't actually change until focus leaves the radio button. And as with all WinForms controls the focus doesn't actually leave the radio button until after focus is given to another control, and in fact not until after the Click event of the newly focused control has fired. The result of this, as it pertains to radio buttons, is that if you try to bind to them, the bound properties in your datasource will actually lag your radio buttons' visual state by one click. If you have just two radio buttons, the datasource will be exactly opposite the visible state, until you click somewhere else that doesn't trigger an action that references those datasource properties. Which can make this a really infuriating bug to track down. I almost thought I was hallucinating.

Now, in all honesty, it's possible to make it work. But it is the kludgiest kludge that ever kludged. Okay maybe it's not that bad... but it's a messy hack for sure. It takes a lot of work for something that really should already be available. As near as I can tell, the only way to solve this problem without giving up the databinding mechanism is to essentially make your own RadioButton control, with a property change and event order that is actually useful. You can either write one from scratch, or sub-class RadioButton and override all the event logic with custom message handling.

Hols answered 26/6, 2010 at 12:0 Comment(0)
R
6

Thanks to Geoffrey Van Wyk and ohadsc (for the link), I came up with the following custom control. It's basically a custom frame that will implement Geoffrey's code automatically on all radiobuttons contained in it. The advantage is that you can now use ApplicationSettings to bind the checked property of the control, and it will work as it is supposed to.

Here's my c# code to make the custom control:

 public partial class RadioPanel : System.Windows.Forms.Panel
    {
        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
            var radioButton = e.Control as RadioButton;
            if (radioButton != null)
                radioButton.Click += radioButton_Click;
        }

        void radioButton_Click(object sender, EventArgs e)
        {
            var radio = (RadioButton)sender;
            if (!radio.Checked)
                radio.Checked = true;
        }

    }
Roux answered 2/8, 2011 at 14:32 Comment(0)
T
3

I can answer this part of your question:

Is there a line of code I need to execute when the form is closed that saves the user settings?

Application settings are stored in your Settings class, in the Properties namespace. The Settings class has a static property called Default, which represents the current settings for your application. So in your main form's Closing event, you call:

Properties.Settings.Default.Save();

... to save the settings.

Likewise you can get to the settings programatically using the setting's name: Properties.Settings.Default.MyRadioButtonState (or whatever you've called it).

Tadich answered 1/6, 2009 at 23:25 Comment(2)
Thanks! That got me going in the right direction. In vb.net it's My.Settings instead of Properties.Settings.Default, but other than that, it works perfectly. I now only have one setting and am using the form's public property in the Load and FormClosing events.Highcolored
On my computer it is not necessary to save the settings on closing. They are saved automatically. The only problem is that I have to click two times.Hols
B
3

This behavior is explained in Item 5 here:

http://turbulentintellect.blogspot.com/2008/07/surviving-winforms-databinding.html

One possible solution would be a custom GroupGox: Best way to databind a group of radiobuttons in WinForms

Bellebelleek answered 6/3, 2010 at 17:42 Comment(1)
Thanks for the answer. I had forgotten about even asking this question!Highcolored

© 2022 - 2024 — McMap. All rights reserved.