This is the experience I just created for a little demo app I'm building with .NET MAUI. Component vendors like Syncfusion and Progress ship SegmentedControls that do this and probably more, but I wanted to see what it would be like to use "in the box" controls. I'm really happy with the result and how easy it was to code. This probably took me 10 minutes.
What I used:
The first two "controls" are really the heart of the solution. The rest are just needed for layout/design.
RadioButton
BindableLayout
HorizontalStackLayout
-
Grid
- perhaps I could have used aVerticalStackLayout
, butGrid
gives me great flexibility Label
-
BoxView
- I like this simple control for painting lines or boxes that need to size to the parent container
The Code
1 - I created my container with a set of data to be repeated for each tab.
<HorizontalStackLayout>
<BindableLayout.ItemTemplate>
<!-- Views Here -->
</BindableLayout.ItemTemplate>
<BindableLayout.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Hot Dishes</x:String>
<x:String>Cold Dishes</x:String>
<x:String>Soups</x:String>
<x:String>Appetizers</x:String>
<x:String>Desserts</x:String>
</x:Array>
</BindableLayout.ItemsSource>
</HorizontalStackLayout>
2 - I created the item template to display a RadioButton
.
<BindableLayout.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding .}" />
</DataTemplate>
</BindableLayout.ItemTemplate>
To make this a grouped list of radios, I added a name to the parent layout.
<HorizontalStackLayout
RadioButtonGroup.GroupName="MenuCategories">
3 - I styled the RadioButton
using a ControlTemplate
.
<RadioButton Content="{Binding .}">
<RadioButton.ControlTemplate>
<ControlTemplate>
<Grid RowDefinitions="30,4">
<Label Text="{TemplateBinding Content}" />
<BoxView Grid.Row="1" Color="Transparent"/>
</Grid>
</ControlTemplate>
</RadioButton.ControlTemplate>
</RadioButton>
Because we are inside of a control template, rather than using Binding
I use TemplateBinding
. The Content
could be anything, but I supplied a String
so it seems safe to bind that directly to the label text.
4 - To get the different look for selected vs unselected, I:
- added a
VisualStateManager
(VSM) to the control template layout - gave my lable and box names so I could target them from the VSM
- styled the checked and unchecked states (odd naming ¯_(ツ)_/¯)
<ControlTemplate>
<Grid RowDefinitions="30,4">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter
TargetName="TextLabel"
Property="Label.TextColor"
Value="{StaticResource Primary}"/>
<Setter
TargetName="Indicator"
Property="BoxView.Color"
Value="{StaticResource Primary}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter
TargetName="TextLabel"
Property="Label.TextColor"
Value="White"/>
<Setter
TargetName="Indicator"
Property="BoxView.Color"
Value="Transparent"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Label Text="{TemplateBinding Content}" x:Name="TextLabel" />
<BoxView x:Name="Indicator" Grid.Row="1" Color="Transparent"/>
</Grid>
</ControlTemplate>
Conclusion
That's it. There are a lot of useful concepts in this example that made implementing it super easy. I hope learned at least one new thing to use in .NET MAUI.
Top comments (2)
I've been trying to implement something like this in C# with no luck, any suggestion will be appreciated.
Simple, clean, elegant