最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

radio button - .NET 9 Maui How to Dynamically Change the Text Color of a RadioButton Based on Its Selection State - Stack Overfl

programmeradmin3浏览0评论

I am trying to customize the appearance of a RadioButton in .NET MAUI, with the goal of dynamically changing the text color based on its selection state (Checked/Unchecked) and using the button's background as a visual indicator for selection. However, I encountered a challenge: I cannot apply the text color directly to the container element (like a Grid or Border) because they do not have a TextColor property.

How can I achieve this effect while ensuring the RadioButton has no checkmark or other icon?

Any help would be greatly appreciated!

<Style TargetType="RadioButton" x:Key="WizardRadioButton">
    <Setter Property="FontFamily" Value="Inter-Bold"/>
    <Setter Property="FontSize" Value="12"/>
    <Setter Property="Margin" Value="0,6,0,6"/>
    <Setter Property="MinimumHeightRequest" Value="44"/>
    <Setter Property="MinimumWidthRequest" Value="44"/>
    <Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}"/>
    <Setter Property="BackgroundColor" Value="Transparent"/>
    <Setter Property="ControlTemplate">
        <Setter.Value>
            <ControlTemplate>
                <Border StrokeThickness="0"
                    Stroke="Transparent"
                    Padding="10,5"
                    BackgroundColor="Transparent"
                        StrokeShape="RoundRectangle 8">
                    <ContentPresenter VerticalOptions="Center"
                                      HorizontalOptions="Center"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CheckedStates">
                            <VisualState x:Name="Checked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="#1CB41C"/>
                                    
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Unchecked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="White"/>
                                    
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I am trying to customize the appearance of a RadioButton in .NET MAUI, with the goal of dynamically changing the text color based on its selection state (Checked/Unchecked) and using the button's background as a visual indicator for selection. However, I encountered a challenge: I cannot apply the text color directly to the container element (like a Grid or Border) because they do not have a TextColor property.

How can I achieve this effect while ensuring the RadioButton has no checkmark or other icon?

Any help would be greatly appreciated!

<Style TargetType="RadioButton" x:Key="WizardRadioButton">
    <Setter Property="FontFamily" Value="Inter-Bold"/>
    <Setter Property="FontSize" Value="12"/>
    <Setter Property="Margin" Value="0,6,0,6"/>
    <Setter Property="MinimumHeightRequest" Value="44"/>
    <Setter Property="MinimumWidthRequest" Value="44"/>
    <Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}"/>
    <Setter Property="BackgroundColor" Value="Transparent"/>
    <Setter Property="ControlTemplate">
        <Setter.Value>
            <ControlTemplate>
                <Border StrokeThickness="0"
                    Stroke="Transparent"
                    Padding="10,5"
                    BackgroundColor="Transparent"
                        StrokeShape="RoundRectangle 8">
                    <ContentPresenter VerticalOptions="Center"
                                      HorizontalOptions="Center"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CheckedStates">
                            <VisualState x:Name="Checked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="#1CB41C"/>
                                    
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Unchecked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="White"/>
                                    
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Share Improve this question edited Feb 16 at 6:44 marc_s 755k184 gold badges1.4k silver badges1.5k bronze badges asked Feb 15 at 22:09 FelixFelix 211 silver badge1 bronze badge New contributor Felix is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 1
  • What platform are you targeting on? – Liqun Shen-MSFT Commented Feb 19 at 7:43
Add a comment  | 

2 Answers 2

Reset to default 1

The ContentPresenter seems to be a Label. So, what you can define a ResourceDictionary in your ContentPresenter to bind Label.TextColor to the Border.Stroke.Color:

<Style x:Key="WizardRadioButton" TargetType="RadioButton">
    <Setter Property="FontFamily" Value="Inter-Bold" />
    <Setter Property="FontSize" Value="12" />
    <Setter Property="Margin" Value="0,6,0,6" />
    <Setter Property="MinimumHeightRequest" Value="44" />
    <Setter Property="MinimumWidthRequest" Value="44" />
    <Setter Property="BackgroundColor" Value="Transparent" />
    <Setter Property="ControlTemplate">
        <Setter.Value>
            <ControlTemplate>
                <Border
                    Padding="10,5"
                    BackgroundColor="Transparent"
                    Stroke="Transparent"
                    StrokeShape="RoundRectangle 8"
                    StrokeThickness="0">
                    <ContentPresenter HorizontalOptions="Center" VerticalOptions="Center">
                        <ContentPresenter.Resources>
                            <ResourceDictionary>
                                <Style TargetType="Label">
                                    <Setter Property="TextColor" Value="{Binding Stroke.Color, x:DataType=Border, Source={RelativeSource AncestorType={x:Type Border}}}" />
                                </Style>
                            </ResourceDictionary>
                        </ContentPresenter.Resources>
                    </ContentPresenter>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CheckedStates">
                            <VisualState x:Name="Checked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="#1CB41C" />
                                    <Setter Property="Stroke" Value="White" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Unchecked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
                                    <Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Stephen’s answer ▲ does a great job using a Style, as the OP requested. To build on that, this answer drills a little deeper into an alternative approach: a custom control for better reusability, maintainability, and extensibility across projects. Since the OP wants a control that "has no checkmark or other icon" (essentially a Button), what if we create OneHotButton and give it a property that binds in XAML markup—e.g., GroupName, whose members behave one-hot, just like a RadioButton group? While we're at it, we can add bindable properties for SelectedTextColor, SelectedBackgroundColor, UnselectedTextColor, and UnselectedBackgroundColor, making it easier to customize the appearance without modifying multiple styles.

<local:OneHotButton Text="Apple" SelectedTextColor="Salmon"  GroupName="OptionsGroup"  IsChecked="true"/>

and

<Style TargetType="local:OneHotButton" >
    <Setter Property="SelectedBackgroundColor" Value="CornflowerBlue"/>
</Style>

Example One Hot Implementation

[DebuggerDisplay("{Text}")]
public partial class OneHotButton : Button
{
    public OneHotButton()
    {
        Clicked += OnButtonClicked;
        UpdateColors();
    }
    private static readonly Dictionary<string, List<OneHotButton>> buttonGroups = new();

    public static readonly BindableProperty GroupNameProperty =
        BindableProperty.Create(
            nameof(GroupName),
            typeof(string),
            typeof(OneHotButton),
            default(string),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                if (bindable is OneHotButton button)
                {
                    if (oldValue is string oldGroup)
                    {
                        buttonGroups[oldGroup].Remove(button);
                        if (buttonGroups[oldGroup].Count == 0)
                            buttonGroups.Remove(oldGroup);

                    }
                    if (newValue is string newGroup && !string.IsNullOrWhiteSpace(newGroup))
                    {
                        if (!buttonGroups.ContainsKey(newGroup))
                            buttonGroups[newGroup] = new List<OneHotButton>();
                        buttonGroups[newGroup].Add(button);
                    }
                }
            });

    public static readonly BindableProperty IsCheckedProperty =
        BindableProperty.Create(
            nameof(IsChecked),
            typeof(bool),
            typeof(OneHotButton),
            false,
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                if (bindable is OneHotButton button &&
                    Equals(newValue, true) &&
                    !string.IsNullOrWhiteSpace(button.GroupName) &&
                    buttonGroups.TryGetValue(button.GroupName, out var buttonList))
                {
                    button.UpdateColors();
                    buttonList
                    .Where(_ => !ReferenceEquals(_, button))
                    .ToList()
                    .ForEach(_ =>
                    {
                        _.IsChecked = false;
                        _.UpdateColors();
                    });
                }
            });
    ...
}

Example Bindable Color

This snippet shows how to expose a property to be used in XAML markup.

public Color SelectedTextColor
{
    get => (Color)GetValue(SelectedTextColorProperty);
    set => SetValue(SelectedTextColorProperty, value);
}

public static readonly BindableProperty SelectedBackgroundColorProperty =
    BindableProperty.Create(
        propertyName: nameof(OneHotButton.SelectedBackgroundColor),
        returnType: typeof(Color),
        declaringType: typeof(OneHotButton),
        defaultValue: Colors.CornflowerBlue,
        defaultBindingMode: BindingMode.OneWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        {
            if (bindable is OneHotButton @this)
            {
                @this.UpdateColors();
            }
        });

private void UpdateColors()
{
    if(IsChecked)
    {
        TextColor = SelectedTextColor;
        BackgroundColor = SelectedBackgroundColor;
    }
    else
    {
        TextColor = UnselectedTextColor;
        BackgroundColor = UnselectedBackgroundColor;
    }
}
... Other bindable colors

XAML Example

<ContentPage xmlns="http://schemas.microsoft/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft/winfx/2009/xaml"
             xmlns:local="clr-namespace:style_radio_group"
             x:Class="style_radio_group.MainPage">

    <ContentPage.Resources>
        <Style TargetType="local:OneHotButton" >
            <Setter Property="SelectedBackgroundColor" Value="CornflowerBlue"/>
            <Setter Property="Margin" Value="25,0"/>
        </Style>
    </ContentPage.Resources>
    <ScrollView>
        <VerticalStackLayout Padding="30,0" Spacing="25">
            <Image 
                Source="dotnet_bot.png"
                HeightRequest="185"
                Aspect="AspectFit"
                SemanticProperties.Description="dot net bot in a race car number eight" />
            <Border Padding="0,0,0,10" StrokeShape="RoundRectangle 10">
                <VerticalStackLayout Spacing="10">
                    <Label
                        Text="Choose One Fruit"
                        Padding="5"
                        BackgroundColor="LightGray"
                        FontSize="16"
                        FontAttributes="Bold"
                        HorizontalOptions="Fill"/>
                    <local:OneHotButton 
                        Text="Apple"
                        SelectedTextColor="Salmon"     
                        GroupName="OptionsGroup"
                        IsChecked="true"/>
                    <local:OneHotButton    
                        Text="Banana"
                        SelectedTextColor="Yellow"
                        GroupName="OptionsGroup"/>
                    <local:OneHotButton   
                        Text="Grape"
                        SelectedTextColor="LightGreen"
                        GroupName="OptionsGroup"/>
                </VerticalStackLayout>
            </Border>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

发布评论

评论列表(0)

  1. 暂无评论