views:

2093

answers:

3

The background

In .Net windows forms (2.0) radio buttons are automatically grouped by their container control, whether it is a Form, Panel or GroupBox.

That means that when you select one radio button, every other radio button in the same container is automatically changed to unchecked state.

Now, consider the following form layout:

MUST HAVE  NICE TO HAVE  DESCRIPTION
---------  ------------  -----------------------------------------------
   [ ]          [ ]      The gizmo works
   [ ]          [ ]      The gizmo works beautifully
   [ ]          [ ]      The gizmo works amazingly and makes you breakfast
   [ ]          [ ]      The gizmo comes with a pony
  • Each '[ ]' is a radio button.
  • The user is asked to choose the required answer in column one, and the optional (desired, best-case answer) in column 2.

As you can see, the radio buttons should be grouped by column: selecting one of the radios should clear the rest of the column, but should have no effect in the other column.

The problem

Basically the problem is that this is a dynamically generated form.

  • The number of rows in the layout is dynamic and it is loaded from a configurable form definition.
  • The description text is not known until runtime and lengths vary a great deal (some might have just a couple of words, and some others a dozen of lines).
  • The layout cannot be redesigned. This comes from the familiarity of the (non-technical) users with the paper version of this form that has been in use for years. This form will also printed and even if I changed the input system on my form that would mean coding another version for printing with the 'old' layout.

What I have tried and didn't work

I first tried to implement this as a dynamically generated layout using 3 panels, one for each column, so the automatic radio button grouping would work just fine. And it did.

But the layout problems related to horizontal alignment between the radio buttons and its text are just killing me. The size of the text is not known until runtime and the text lines might wrap (sometimes several times for each item). Sometimes it aligns properly, sometimes it doesn't. I'm about to start debugging this, but I'm thinking if maybe changing this 3-panel implementation is a better option.

What I'm trying to do

I would like to redesign the layout by using a TableLayoutPanel with 3 columns in order to simplify the alignment related issues, but that means that I cannot use the automatic radio button grouping-by-container "feature".

EDIT:

As Gerrie suggested, other layout option is to have each line implemented as a user control and use a flow layout panel.

That means, again, that I might want to use controls for layout, but not for radio button grouping.

I would need to get vertical radio button groups despite using horizontal user controls

/EDIT

What I'm trying to ask

I need pointers and suggestions about how to manually control the grouping of the radio buttons. I really don't mind subclassing the RadioButton class if needed.

Specifically, is there any 'canonical' or known way of subclassing 'RadioButton' or go all the way down to Win32 APIs, so that every time the control is checked (by using the mouse, keyboard Enter, Space bar, and any other way that I could not be aware of selecting them) I can trap the event and manually update the state of every other control on my form and in a way that the automatic grouping feature is well known to be 'de-activated'? I fear that the implementation is also container-related and I might be also forced to subclass Panel?.

Does anyone has insights on how the grouping 'magic' works in winforms?

Every solution I have found googling that implements custom radio button groups or 'radio button lists' is based in some way in using a container for the group. I have not been able to find whether containers can be avoided and how.

+1  A: 

I would go for a simple and straightforward solution, for example a custom control that represents one line (so two radio buttons and a label).

EDIT: ok I think I understand your requirement now. Can't you just have two collections of radiobuttons: the ones in column A and the ones in column B. When your form is drawn add them to two List or whatever and bind them to two seperate events: columnARBChecked, columnBRBChecked. When one of the events fire you can call some logic to check/uncheck the rest of the radiobuttons as you please.

Gerrie Schenck
That would work instead of the TableLayoutPanel for layout purposes, sure. The problem with this solution is that the buttons inside the user control would be still grouped inside the user control. So I would have as many groups as user control instances instead of 2 groups (one for each column).
Sergio Acosta
Then I'm afraid I don't understand your requirement completely. You want horizontal grouping right? Why do you want vertical panels as well? Why can't you just loop over the collection of custom controls and read which radio button is checked there?
Gerrie Schenck
Sorry, I will edit the question to clarify that in fact horizontal grouping (that is what would happen by default) is not what I need, but vertical grouping. thanks.
Sergio Acosta
The problem is not at knowing which controls are checked. The problem is that winforms automatically unchecks the other radio buttons when the user checks one of them if they are in the same container. I don't want that to happen.
Sergio Acosta
Regarding your edit: Yes, that's what I'm planing to do. The problem was how to avoid winforms managing the checked value. That's why came up my temporal solution of adding each button inside their own panel. For now the question, more general, is how to disable winforms auto grouping radio buttons.
Sergio Acosta
+1  A: 

Ok, sorry for answering my own question. You know that when you take the time to explain something you start seeing the problem it a different light.

A temporal solution (read: messy hack) I found is that I'm putting each and every radio button in its own small panel. So no grouping at all happens between any of them. I'm listening to every button Checked events and updating the appropriate ones accordingly.

I still think it is overkill to have that many panels, and if anyone has a cleaner solution I'd love to hear it.

Sergio Acosta
If you are going with this solution, then it would be a good time to create an own radiobutton that doesnt have to be in an panel. And when you are at it, add a optional property GroupID, that is sent back when toggled.
Stefan
Again, thanks for your help Stefan. By the way, I had already made an IndependentRadioButton class but it didn't occurred to me yet to add the GroupId property right there. Sounds just right.
Sergio Acosta
Check the edit of my answer for some more ideas.
Gerrie Schenck
You are just using the wrong kind of control. These should be checkboxes.
Hans Passant
@nobugz: Textboxes that become unchecked when the user checks another one? No, that's what radio buttons are for. Thanks.
Sergio Acosta
+1  A: 
Stefan
Yes, this is in my opinion even more appropriate than using radio buttons. Two show-stoppers though: first, the requirement specifies the use of radio buttons; and second, the length of the text that would go in the combobox is sometimes quite larger than the screen, and it would become unreadable.
Sergio Acosta