Increasing the hit size of a radio button
Asked Answered
M

3

7

I've been using Windows Forms for years, but I'm relatively new to WPF. I have a number of radio buttons without labels (the labels are at the top of the column, don't worry about them! This program is going to run on a tablet so I want to make the hit area for the radio buttons as large as possible. I also need the radio buttons to be in the center of their column and row.

I can get the look I want by adding this to each column of my grid:

<Label Name="connectedLabel" Grid.Column="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
    <RadioButton x:FieldModifier="private" Name="connectedRadioButton" Grid.Column="2" Checked="otherRadioButton_CheckedChanged" Unchecked="otherRadioButton_CheckedChanged"></RadioButton>
</Label>

Which just centers a radio button within a label that fills the grid section.
Obviously the behaviour is all wrong though (events don't pass through, you can select multiple radiobuttons on the same row, etc.).

This would be cake in Winforms, I'm hoping there's a simple solution in WPF.

Can anybody help?

Edit: The orange area is the default hit area for the radio button, the green area is the hit area I want. So far this is looking impossible without a lot of custom wiring

enter image description here

Mastrianni answered 31/8, 2011 at 5:32 Comment(4)
Have you tried stretch properties? Have you tried setting properties on the radio button itself, such as content alignment? Is your grid inside any sort of panel (because that breaks stretching)? Have you tried a border instead of a label?Ulm
Hi Merlyn, yes I have tried stretch properties, I've tried all the likely properties on the radio button itself (including content alignment). The grid is directly under my user control (that user control is then being added to an item panel, but that couldn't be a problem surely?). Borders don't allow content alignment, which leaves the radio button in the top left.Mastrianni
+1 on the question now that you have the screenshots. This makes it much more clear what you're looking for.Ulm
I've just edited my answer. Hopefully I have set out the containers in a manner similar to what you have.Crucifer
C
11

Edit per new image in question.

If you don't mind the extra typing you can use this:

        <Style TargetType="RadioButton" x:Key="rb">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RadioButton">
                        <Grid>
                            <RadioButton IsChecked="{Binding Path=IsChecked, RelativeSource={RelativeSource Mode=TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <Border Background="Transparent" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

This works as expected in my little test app of:

<Grid>
    <Grid.Resources>
        <Style TargetType="RadioButton" x:Key="rb">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RadioButton">
                        <Grid>
                            <RadioButton IsChecked="{Binding Path=IsChecked, RelativeSource={RelativeSource Mode=TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <Border Background="Transparent" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="ics">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid ShowGridLines="True">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>

                            <RadioButton HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <RadioButton HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="1" />
                            <RadioButton Style="{StaticResource rb}" Grid.Column="2" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>

    <ListBox ItemContainerStyle="{StaticResource ics}">
        <ListBoxItem>1</ListBoxItem>
    </ListBox>
</Grid>

Which looks like:

enter image description here

(Obviously you will want to use the third method provided)

I know this doesn't look like much, but it gives you your result. Again, excuse the extra typing and the lack of coding standards used.

For this, the mouse hover-over won't give the visual effect, but the hit-test is valid. I assume this will be OK so long as this will be on a tablet and you don't track fingers.


If you just want the control to be of larger size you could use the following methods

You can resize a control by setting the RenderTransform property to a ScaleTransform object.

Resize all RadioButton objects within a container (Window, Page, Grid etc)

<Window.Resources>
    <Style TargetType="RadioButton">
        <Setter Property="RenderTransform">
            <Setter.Value>
                <ScaleTransform ScaleX="10" ScaleY="10"/>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Or all with key

    <Style TargetType="RadioButton" x:Key="resizeRadioButton">
        <Setter Property="RenderTransform">
            <Setter.Value>
                <ScaleTransform ScaleX="10" ScaleY="10"/>
            </Setter.Value>
        </Setter>
    </Style>

Usage:

<RadioButton Style="{StaticResource resizeRadioButton}" />

Or individually

<RadioButton>
    <RadioButton.RenderTransform>
        <ScaleTransform ScaleX="10" ScaleY="10"/>
    </RadioButton.RenderTransform>
</RadioButton>

If however you want to use a combination of larger control and larger hit area (or just larger hit area for all controls of a set type), you can use:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style TargetType="RadioButton">
        <Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment" Value="Center" />

        <Setter Property="RenderTransform">
            <Setter.Value>
                <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
            </Setter.Value>
        </Setter>

       <Setter Property="Content">
           <Setter.Value>
               <Border>
                   <Rectangle Margin="-10" Fill="Transparent" />
               </Border
           </Setter.Value>
       </Setter>
    </Style>

</ResourceDictionary>

Or just use the default behaviour of the control inside another container, and use the HorizontalAlignment="Stretch" property, this will however draw the control in the upper-left corner I believe.

Crucifer answered 31/8, 2011 at 5:50 Comment(7)
@Justin - ...and, you don't need the Label. Use HorizontalAlignment="Center" VerticalAlignment="Center" on the RadioButton. Also, stukselbax bellow, has a great and essential piece of information about GroupName.Blanka
@Blanka Thanks, I know I shouldn't need the label, it's a hack, I just wanted to give some idea of what I'm after. I didn't consider it an acceptable solution since I'd have to wire up mouseover and click events. I've been sidetracked by something else atm. I'll be back soonMastrianni
In regard to this answer, while very useful to know in a general sense, isn't what I'm after. I want the hit box on the radio button to be larger, I don't want a bigger radio button. Thank you for the suggestion thoughMastrianni
Figured that if this was on a tablet, you would want either the control to be larger for the user. You could use a combination of your method and mine. See answer update (when I finish writing it)Crucifer
Thanks again, I really appreciate the effort you've put into this but the hit area is still to the right or left of the radio button. I've added an image to my question that will hopefully make it clearer.Mastrianni
Mouse over isn't an issue (stylus, but same principal). The hit test has problems though. It hits, and the checked event fires but you need to click twice to get the checked appearance to show (the green dot in the center). I'll accept this anyway and try to work out the visual problem. Thanks a million.Mastrianni
It was a custom event that stopped it working (from earlier fiddling). The top method works for me, no problems. You're a champion.Mastrianni
H
1

GroupName property of RadioButton should help. Set it in each RadioButton the same, gl & hf!

<RadioButton GroupName="MyGroup1">
<RadioButton GroupName="MyGroup1">
<RadioButton GroupName="MyGroup1">
<RadioButton GroupName="MyGroup2">
<RadioButton GroupName="MyGroup2">
<RadioButton GroupName="MyGroup3">

each group will work as expected. only one RadioButton in group will be checked.

Hulking answered 31/8, 2011 at 5:49 Comment(1)
Thanks sukselbax, this is very useful to know and might even be a partial solution, but what I really want is to increase the whitespace around the radiobutton circle. In Winforms I just turn off autosize, centre the 'checkbox' and dock the whole thing. I just need a WPF equivalentMastrianni
B
1

[I'm just adding upon the solutions of fatty and stukselbax]

It seems that you'll need to change the Template of the RadioButton. Bellow is a default Aero (Win7) style with a modified template, see the comment in the code. For the code to work, add this namespace: xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" and make sure you reference the PresentationFramework.Aero.dll assembly.

<Style x:Key="CheckRadioFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style TargetType="{x:Type RadioButton}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background" Value="#F4F4F4"/>
    <Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type RadioButton}">
                <BulletDecorator Background="Transparent">
                    <BulletDecorator.Bullet>
                        <Grid>
                            <!--This is where you decide about the size of the hit area, the Border bellow has to be transparent and it's acting as the hit area. The Width and Height on the BulletChrome is a modification to bring the size of the bullet back to original size (or close to it)-->
                            <Border Background="Transparent" Width="50" Height="50"/>
                            <Microsoft_Windows_Themes:BulletChrome Width="20" Height="20" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" IsRound="true" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
                        </Grid>
                    </BulletDecorator.Bullet>
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </BulletDecorator>
                <ControlTemplate.Triggers>
                    <Trigger Property="HasContent" Value="true">
                        <Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
                        <Setter Property="Padding" Value="4,0,0,0"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Blanka answered 5/9, 2011 at 8:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.