You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI:如何让带ControlTemplate的RadioButton占满全部可用空间?

问题

我需要实现一个水平选择列表,让列表项在视图中均匀分布。为此我使用FlexLayout,并通过BindableLayout填充选择数据。但RadioButton始终无法占据全部可用区域,且手动设置WidthRequest不可行——因为视图宽度或可选选项数量可能变化。

我是否遗漏了什么设置?在多个元素上设置VerticalOptions为Fill并未生效。

当前状态:黑色边框的FlexLayout已均匀分配空间,但内部RadioButton仅占据中间部分;期望效果:RadioButton填满整个边框区域,实现等分的选项卡效果。

FlexLayout的XAML代码如下:

<FlexLayout Background="Gray"
            HeightRequest="100"
            JustifyContent="SpaceEvenly"
            AlignItems="Stretch">
<!-- Demo items for testing -->
<BindableLayout.ItemsSource>
    <x:Array Type="{x:Type x:String}">
        <x:String>1</x:String>
        <x:String>2</x:String>
        <x:String>3</x:String>
    </x:Array>
</BindableLayout.ItemsSource>
<BindableLayout.ItemTemplate>
    <DataTemplate>
        <!--Border to show that Flexlayout is behaving as expected-->
        <Border FlexLayout.Grow="1"
                Background="Transparent"
                Stroke="Black"
                StrokeThickness="2"
                StrokeShape="RoundRectangle 10">
            <!--This should occupy all the space available--> 
            <RadioButton Content="{Binding .}" HorizontalOptions="Center" FlexLayout.Grow="1">
                <RadioButton.ControlTemplate>
                    <ControlTemplate>
                        <Grid BackgroundColor="Cyan">
                            <Border Background="Orange"
                                    StrokeShape="RoundRectangle 10">
                            <Label Text="{TemplateBinding Content}"
                                   HorizontalOptions="Center"
                                   VerticalOptions="Center"/>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </RadioButton.ControlTemplate>
            </RadioButton>
        </Border>
    </DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>

补充:临时实现方案(通过C#代码动态创建Grid列和元素):

internal void ReorderItems(IEnumerable<SelectionModel> items)
{
    ContentGrid.Clear();
    ContentGrid.ColumnDefinitions.Clear();

    int counter = 0;
    foreach (var item in items)
    {
        ContentGrid.ColumnDefinitions.Add(new ColumnDefinition());
        Frame background = new()
        {
            HeightRequest = 44,
            HorizontalOptions = LayoutOptions.Fill,
            CornerRadius = 8,
            BorderColor = Colors.Transparent,
            Padding = 0,
            Style = Resources["NormalStyle"] as Style
        };
        //Selected item is a bindable property on the control
        if (SelectedItem is not null && item.Number == SelectedItem.Number)
            background.Style = Resources["SelectedStyle"] as Style;

        TapGestureRecognizer tapRecognizer = new()
        {
            Command = SelectionChangedCommand,
            CommandParameter = item,
        };
        background.GestureRecognizers.Add(tapRecognizer);
        
        Label numberLabel = new()
        {
            Text = item.Number.ToString(),
            TextColor = Color.FromArgb("#6D6D6D"),
            FontSize = 14,
            VerticalOptions = LayoutOptions.Center,
        };

        Image defaultImage = new()
        {
            Source = item.IsLocked ?
                _lockImageSource : item.IsFinished ?
                _finishedSource : item.IsStarted ?
                _startedSource :
                _notStartedSource,
            HeightRequest = 24,
            WidthRequest = 24,
            VerticalOptions = LayoutOptions.Center,
        };

        HorizontalStackLayout centerLayout =
        [
            numberLabel, defaultImage
        ];
        centerLayout.HorizontalOptions = LayoutOptions.Center;
        centerLayout.Spacing = 8;
        centerLayout.HeightRequest = 24;

        background.Content = centerLayout;

        ContentGrid.Add(background, counter, 0);

        counter++;
    }
}

解决方案

问题出在两个核心设置缺失:

  1. RadioButton的HorizontalOptions设为Center,导致它仅占据自身内容宽度,而非填充父容器;
  2. ControlTemplate内部的Grid和Border未配置填充父容器的属性。

修改步骤

1. 调整RadioButton布局属性

将RadioButton的HorizontalOptions改为Fill,保留FlexLayout.Grow="1"确保均分空间:

<RadioButton Content="{Binding .}" HorizontalOptions="Fill" FlexLayout.Grow="1">

2. 修改ControlTemplate内部布局

让ControlTemplate中的Grid和Border完全填充RadioButton的空间,同时可添加Padding优化内容间距:

<RadioButton.ControlTemplate>
    <ControlTemplate>
        <Grid BackgroundColor="Cyan" HorizontalOptions="Fill" VerticalOptions="Fill">
            <Border Background="Orange"
                    StrokeShape="RoundRectangle 10"
                    HorizontalOptions="Fill"
                    VerticalOptions="Fill"
                    Padding="8">
                <Label Text="{TemplateBinding Content}"
                       HorizontalOptions="Center"
                       VerticalOptions="Center"/>
            </Border>
        </Grid>
    </ControlTemplate>
</RadioButton.ControlTemplate>

完整修改后的XAML代码

<FlexLayout Background="Gray"
            HeightRequest="100"
            JustifyContent="SpaceEvenly"
            AlignItems="Stretch">
<!-- Demo items for testing -->
<BindableLayout.ItemsSource>
    <x:Array Type="{x:Type x:String}">
        <x:String>1</x:String>
        <x:String>2</x:String>
        <x:String>3</x:String>
    </x:Array>
</BindableLayout.ItemsSource>
<BindableLayout.ItemTemplate>
    <DataTemplate>
        <!--Border to show that Flexlayout is behaving as expected-->
        <Border FlexLayout.Grow="1"
                Background="Transparent"
                Stroke="Black"
                StrokeThickness="2"
                StrokeShape="RoundRectangle 10">
            <!--This should occupy all the space available--> 
            <RadioButton Content="{Binding .}" HorizontalOptions="Fill" FlexLayout.Grow="1">
                <RadioButton.ControlTemplate>
                    <ControlTemplate>
                        <Grid BackgroundColor="Cyan" HorizontalOptions="Fill" VerticalOptions="Fill">
                            <Border Background="Orange"
                                    StrokeShape="RoundRectangle 10"
                                    HorizontalOptions="Fill"
                                    VerticalOptions="Fill"
                                    Padding="8">
                                <Label Text="{TemplateBinding Content}"
                                       HorizontalOptions="Center"
                                       VerticalOptions="Center"/>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </RadioButton.ControlTemplate>
            </RadioButton>
        </Border>
    </DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>

原理说明

  • FlexLayout.Grow="1"让每个Border及内部RadioButton均分FlexLayout的可用水平空间;
  • HorizontalOptions="Fill"确保RadioButton、Grid、Border都填充父容器宽度;
  • 内部Border的Padding可调整内容与边框的间距,提升视觉舒适度。

修改后RadioButton将完全填充分配的空间,实现期望的等分效果,无需依赖C#动态创建控件的临时方案。

内容的提问来源于stack exchange,提问作者Dokug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 09:03:15