Home > Mobile >  Issues with styling a radio button in .Net MAUI
Issues with styling a radio button in .Net MAUI

Time:01-24

I am running into some issues with styling a radio button in .Net MAUI. Initially, I noticed the the radio button look-and-feel is not consistent across Windows and Android, as can be seen in the image below:

Radio button look-and-feel

Not only are they different, but the available options for styling the button are limited. The only options for defining colors are "BorderColor", "BackgroundColor", and "TextColor". Both "BorderColor" and "BackgroundColor" have absolutely no effect on the color of the radio button itself. I'd like to change the color of the actual radio button.

So I decided to create a control template to help me out. Here is my control template:

<ControlTemplate x:Key="RadioButtonTemplate">
    <Border Stroke="Transparent" BackgroundColor="Transparent">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroupList>
                <VisualStateGroup x:Name="CheckedStates">
                    <VisualState x:Name="Checked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="1" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Unchecked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="0" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateGroupList>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
                <Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="DarkBlue" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
                <Ellipse x:Name="check" Fill="DarkBlue" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
            </Grid>
            <ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
        </Grid>
    </Border>
</ControlTemplate>

<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
    <Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
</Style>

This worked reasonably well, so now I get the following look-and-feel on both Android and Windows:

Updated radio button look-and-feel

Now I have one last problem. When I was using the default radio buttons (without my control template), they would reliably turn a "light gray" color whenever I set IsEnabled to false. I'd like to make it so that I can disable my radio button and have it turn a light gray color (to indicate that it is disabled) while still using my control template so I have a unified look-and-feel.

So I attempted to add a Disabled visual state to my control template, but it doesn't seem to be working. Here is my new control template with a Disabled state:

<ControlTemplate x:Key="RadioButtonTemplate">
    <Border Stroke="Transparent" BackgroundColor="Transparent">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroupList>
                <VisualStateGroup x:Name="CheckedStates">
                    <VisualState x:Name="Checked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="1" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Unchecked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="0" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Disabled">
                        <VisualState.Setters>
                            <Setter TargetName="border_circle" Property="Stroke" Value="LightGray" />
                            <Setter TargetName="check" Property="Fill" Value="LightGray" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateGroupList>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
                <Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="DarkBlue" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
                <Ellipse x:Name="check" Fill="DarkBlue" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
            </Grid>
            <ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
        </Grid>
    </Border>
</ControlTemplate>

<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
    <Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
</Style>

Unfortunately, it's not working. Not only does the color not change when the radio button is disabled, but also my 2nd setter (setting the "Fill" property of the "check" object) causes a compile-time error as well ("Cannot resolve property Fill on type Border").

Any suggestions?

CodePudding user response:

I was able to figure out a way to do what I needed to do. Rather than use the "Disabled" visual state in the visual state group, I was able to use style triggers. So now my control template and its corresponding style look like this:

<ControlTemplate x:Key="RadioButtonTemplate">
    <Border Stroke="Transparent" BackgroundColor="Transparent">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroupList>
                <VisualStateGroup x:Name="CheckedStates">
                    <VisualState x:Name="Checked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="1" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Unchecked">
                        <VisualState.Setters>
                            <Setter TargetName="check" Property="Opacity" Value="0" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateGroupList>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
                <Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="{TemplateBinding BorderColor}" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
                <Ellipse x:Name="check" Fill="{TemplateBinding BorderColor}" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
            </Grid>
            <ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
        </Grid>
    </Border>
</ControlTemplate>

<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
    <Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
    <Style.Triggers>
        <Trigger TargetType="RadioButton" Property="IsEnabled" Value="False">
            <Setter Property="BorderColor" Value="LightGray" />
        </Trigger>
        <Trigger TargetType="RadioButton" Property="IsEnabled" Value="True">
            <Setter Property="BorderColor" Value="DarkBlue" />
        </Trigger>
    </Style.Triggers>
</Style>
  • Related