Skip to content

Instantly share code, notes, and snippets.

@gpproton
Last active May 22, 2024 10:57
Show Gist options
  • Save gpproton/181a9263721be1dc6625ae44e1eccc19 to your computer and use it in GitHub Desktop.
Save gpproton/181a9263721be1dc6625ae44e1eccc19 to your computer and use it in GitHub Desktop.
A basic dotnet MAUI sample segment control example using BindableLayout
<!-- Working code -->
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XClaim.Mobile.Views.Segment"
x:Name="this">
<Border Padding="3" StrokeThickness="0" BackgroundColor="{DynamicResource Tertiary}">
<Border.StrokeShape>
<RoundRectangle>
<RoundRectangle.CornerRadius>
<CornerRadius>10</CornerRadius>
</RoundRectangle.CornerRadius>
</RoundRectangle>
</Border.StrokeShape>
<ScrollView>
<FlexLayout BindableLayout.ItemsSource="{Binding Source={x:Reference this},Path=SegmentItems}" RadioButtonGroup.SelectedValue="{Binding Source={x:Reference this},Path=SelectedItem}" MinimumHeightRequest="40" Wrap="NoWrap" JustifyContent="SpaceBetween" RadioButtonGroup.GroupName="SegmentRadios">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="{x:Type x:String}">
<RadioButton FlexLayout.Basis="50%" Content="{Binding .}" Value="{Binding .}">
<RadioButton.ControlTemplate>
<ControlTemplate>
<Grid VerticalOptions="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter TargetName="SegmentItem" Property="Button.TextColor" Value="{DynamicResource White}" />
<Setter TargetName="SegmentItem" Property="Button.BackgroundColor" Value="{DynamicResource Primary}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter TargetName="SegmentItem" Property="Button.TextColor" Value="{DynamicResource Primary}" />
<Setter TargetName="SegmentItem" Property="Button.BackgroundColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Button x:Name="SegmentItem" Clicked="OnItemClicked" HorizontalOptions="Fill" Text="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</RadioButton.ControlTemplate>
</RadioButton>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
</ScrollView>
</Border>
</ContentView>
// Working code
// Maui.BindableProperty.Generator for clean bindable properties
#pragma warning disable
#nullable enable
namespace XClaim.Mobile.Views;
public partial class Segment : ContentView
{
[AutoBindable]
private readonly string[]? _segmentItems;
[AutoBindable]
private readonly string? _selectedItem;
public enum ItemState { Pending, Confirmed, Completed }
public Segment() {
InitializeComponent();
if(SegmentItems is null) SegmentItems = Enum.GetNames(typeof(ItemState));
if(SegmentItems is not null) SelectedItem = SegmentItems[0];
}
async void OnItemClicked(object sender, EventArgs args) {
SelectedItem = (sender as Button).Text;
}
}
// Not working - Unable to bind VisualStateGroup
// Still trying to implement this with only code
public class SegmentCode : Border {
readonly string[] items = { "Pending", "Confirmed", "Completed" };
// Extending is not equivalent to X:Name, looking for a solution
class SegmentButton : Button {
public SegmentButton() => this.Margins(0, 0, 8, 0);
}
public SegmentCode() {
Padding = 3;
Margin = 8;
StrokeShape = new RoundRectangle {
CornerRadius = new CornerRadius(10)
};
SetDynamicResource(BackgroundColorProperty, "Tertiary");
var layout = new HorizontalStackLayout()
.ItemsSource(items)
.ItemTemplate(new DataTemplate(() => new RadioButton {
ControlTemplate = new ControlTemplate(() => new SegmentButton()
.Bind(Button.TextProperty, "Content", source: RelativeBindingSource.TemplatedParent))
}.Bind(RadioButton.ContentProperty)));
RadioButtonGroup.SetGroupName(layout, "SegmentRadios");
// Todo: Add VisualStateGroup to the baindable layout
// Todo: Properly name child crontrols to reference in VistualState
var vsGroups = new VisualStateGroup() {
Name = "CheckedStates",
};
vsGroups.States.Add(new VisualState {
Name = "Checked",
Setters = {
new Setter { TargetName = nameof(SegmentButton), Property = Button.BackgroundColorProperty, Value = Colors.Indigo }
}
});
vsGroups.States.Add(new VisualState {
Name = "Unchecked",
Setters = {
new Setter { TargetName = nameof(SegmentButton), Property = Button.BackgroundColorProperty, Value = Colors.Transparent },
new Setter { TargetName = nameof(SegmentButton), Property = Button.TextColorProperty, Value = Colors.Indigo }
}
});
var vsList = new VisualStateGroupList();
vsList.Add(vsGroups)
VisualStateManager.SetVisualStateGroups(layout, vsGroups);
Content = layout;
}
}
@gpproton
Copy link
Author

gpproton commented Nov 6, 2022

My real goal is to properly implement this control in C# Markup, and i've been hit a lot of roadblock as there's not enough information on using VisualStateGroupList and BindableLayout together with C# Markup, so any help be appreciated.

Screenshot_1667754870

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment