How can I reduce RadioButton binding code?
Asked Answered
B

1

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?

Bilander answered 4/2, 2012 at 23:36 Comment(2)
Related: stackoverflow.com/questions/6258505 (My answer using an ItemsControl might be helpful, you could use a UniformGrid as panel).Jarad
@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?Bilander
J
9

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>
Jarad answered 5/2, 2012 at 0:34 Comment(6)
I found this helpful as well: msdn.microsoft.com/en-us/library/bb613576.aspx. @H.B. you're amazing mate.Haletky
I prefer: #398056 but I cannot not say that reusing ListBox for it is actually quite sly ;)Metamorphic
@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), especially for large enums 2. The code is unncessarily long.Jarad
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.Metamorphic
@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.Jarad
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.Metamorphic

© 2022 - 2024 — McMap. All rights reserved.