5

I'm following this answer on how to databind enums (ints in my case) to RadioButtons, but if I've got several TabItems each with 10x10 grids of RadioButtons, is there any way to get rid of some of that boilerplate? As is, each RadioButton has to have all this info with it:

<RadioButton 
    IsChecked="{Binding  
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},  
        Path=FavoriteColor,
        Converter={StaticResource IntToBoolConverter},
        Mode=TwoWay,
        ConverterParameter=5}" 
    Content="Red" Grid.Column="4" Grid.Row="6" />

Preferably I'd like to be able to set the RelativeSource, the Converter, and the Mode once in the TabControl, the Path once in each TabItem, and only have the ConverterParameter set per RadioButton. Is this possible in XAML? If not, would doing it in codebehind make more sense?

Community
  • 1
  • 1
Dax Fohl
  • 10,654
  • 6
  • 46
  • 90
  • Related: http://stackoverflow.com/questions/6258505/ (My answer using an `ItemsControl` might be helpful, you could use a `UniformGrid` as panel). – H.B. Feb 04 '12 at 23:41
  • @H.B. Ooh, so would that mean I'd not only be able to get rid of the Binding boilerplate, but I'd be able to get rid of all the RadioButton definitions as well? – Dax Fohl Feb 05 '12 at 00:00

1 Answers1

8

Here would be an improvement on my answer on a related question, utilizing the single selection mode of ListBoxes:

<ListBox SelectionMode="Single" SelectedItem="{Binding EnumValue}"
        Style="{StaticResource BorderlessStyle}">
    <ListBox.Resources>
        <ObjectDataProvider x:Key="items" MethodName="GetValues"
                            ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:MainWindow+TestEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </ListBox.Resources>
    <ListBox.ItemsSource>
        <Binding Source="{StaticResource items}" />
    </ListBox.ItemsSource>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <!-- Automatic grid layout, adjust as needed -->
            <UniformGrid Columns="2" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <RadioButton Content="{Binding}"
                    IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

The style to make the ListBox itself disappear:

<Style x:Key="BorderlessStyle" TargetType="ListBox">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <ItemsPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>
Community
  • 1
  • 1
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • I found this helpful as well: http://msdn.microsoft.com/en-us/library/bb613576.aspx. @H.B. you're amazing mate. – Blake Mumford Jun 09 '12 at 00:56
  • I prefer: http://stackoverflow.com/questions/397556/how-to-bind-radiobuttons-to-an-enum but I cannot not say that reusing ListBox for it is actually quite sly ;) – quetzalcoatl Aug 08 '12 at 13:28
  • @quetzalcoatl: You link to a question, are you referring to the accepted answer? If so: That is a really bad solution because 1. It is a nightmare to maintain because of all the hardcoded values and the redundancy ([DRY](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)), especially for large enums 2. The code is unncessarily long. – H.B. Aug 08 '12 at 13:42
  • Sorry, I referred to the second answer, but pasted wrong link. I'm unable to fix the comment :/ It is NOT a bad solution, but another approach. Your solution isnt shorter, just check how many XAML lines and listboxes you have to inject everwhere versus single-line binding + reusable converter. Your cannot freely distribute the radios across window and must have all packed in ListBox (neglible), may have problems with manual-styling for individual Radios, etc. Your approach is probably the best for mass-production of radios for long choices. Theirs is the best for a few manually placed radios. – quetzalcoatl Aug 08 '12 at 14:27
  • @quetzalcoatl: It does not matter if my code is long, you can easily extract it to a UserControl, then you can have radio button groups everywhere with *one line of code*. The panels give you more than enough control about destribution so manual placement does not seem like a valid point to me *especially because scattered items that belong together is bad UI design*. So as i see it is a bad solution, the only advantage the linked answer has over the accepted one is additional type safety which mine has implicitly. – H.B. Aug 08 '12 at 14:36
  • I already said that the layout/grouping is the first thing to notice but it is **negligble**. Of course you can pack it into a UserControl 'RadioButtonGroup'. Then,eventually you will have to externalize the layout panel, row styling, etc. just like I recently had to do, and it will get uglier. And might fail at a trivial thing like setting a background of fourth Radio. Both solutions have their own tradeoffs, and this is why I didn't say that the second is better. I prefer it. Once I have a 88 entries to choose from, I will wrap them in ListBox/ItemsControl. But if I have 2 or 3 - will not. – quetzalcoatl Aug 08 '12 at 14:53