Building a Custom Checkbox Control
This post is a code dump for a custom checkbox control.
There’s four main parts for this:
Custom Control
* Bindings
* XAML
Host Page
* XAML
* Viewmodel
Bindings
public partial class CheckMark : ContentView { public CheckMark() { InitializeComponent(); } public static readonly BindableProperty SelectionCommandProperty = BindableProperty.Create("SelectionCommand", typeof(ICommand), typeof(CheckMark), null); public ICommand SelectionCommand { get { return (ICommand)GetValue(SelectionCommandProperty); } set { SetValue(SelectionCommandProperty, value); } } public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(CheckMark), null); public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static BindableProperty BoxColorProperty = BindableProperty.Create( propertyName: "BoxColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color BoxColor { get { return (Color) GetValue(BoxColorProperty); } set { SetValue(BoxColorProperty, value); } } public static BindableProperty SelectedBoxColorProperty = BindableProperty.Create( propertyName: "SelectedBoxColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color SelectedBoxColor { get { return (Color)GetValue(SelectedBoxColorProperty); } set { SetValue(SelectedBoxColorProperty, value); } } public static BindableProperty DeselectedBoxColorProperty = BindableProperty.Create( propertyName: "DeselectedBoxColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color DeselectedBoxColor { get { return (Color)GetValue(DeselectedBoxColorProperty); } set { SetValue(DeselectedBoxColorProperty, value); } } public static BindableProperty TextProperty = BindableProperty.Create( propertyName: "Text", returnType: typeof(string), declaringType: typeof(CheckMark), defaultValue: "", defaultBindingMode: BindingMode.TwoWay); public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static BindableProperty TextColorProperty = BindableProperty.Create( propertyName: "TextColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Black, defaultBindingMode: BindingMode.TwoWay); public Color TextColor { get { return (Color)GetValue(TextColorProperty); } set { SetValue(TextColorProperty, value); } } public static BindableProperty DeselectedTextColorProperty = BindableProperty.Create( propertyName: "DeselectedTextColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color DeselectedTextColor { get { return (Color)GetValue(DeselectedTextColorProperty); } set { SetValue(DeselectedTextColorProperty, value); } } public static BindableProperty FontSizeProperty = BindableProperty.Create( propertyName: "FontSize", returnType: typeof(int), declaringType: typeof(CheckMark), defaultValue: 18, defaultBindingMode: BindingMode.TwoWay); public int FontSize { get { return (int)GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } public static BindableProperty SelectedTextColorProperty = BindableProperty.Create( propertyName: "SelectedTextColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color SelectedTextColor { get { return (Color)GetValue(SelectedTextColorProperty); } set { SetValue(SelectedTextColorProperty, value); } } public static BindableProperty SelectedBackgroundColorProperty = BindableProperty.Create( propertyName: "SelectedBackgroundColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color SelectedBackgroundColor { get { return (Color)GetValue(SelectedBackgroundColorProperty); } set { SetValue(SelectedBackgroundColorProperty, value); } } public static BindableProperty DeselectedBackgroundColorProperty = BindableProperty.Create( propertyName: "DeselectedBackgroundColor", returnType: typeof(Color), declaringType: typeof(CheckMark), defaultValue: Color.Transparent, defaultBindingMode: BindingMode.TwoWay); public Color DeselectedBackgroundColor { get { return (Color)GetValue(DeselectedBackgroundColorProperty); } set { SetValue(DeselectedBackgroundColorProperty, value); } } void CheckBox_CheckedChanged(object sender, CheckedChangedEventArgs e) { if (e.Value) { BoxColor = SelectedBoxColor; TextColor = SelectedTextColor; BackgroundColor = SelectedBackgroundColor; } else { BoxColor = DeselectedBoxColor; TextColor = DeselectedTextColor; BackgroundColor = DeselectedBackgroundColor; } object resolvedParameter; if (CommandParameter != null) resolvedParameter = CommandParameter; else resolvedParameter = e; if (SelectionCommand?.CanExecute(resolvedParameter) ?? true) SelectionCommand?.Execute(resolvedParameter); } void TapGestureRecognizer_Tapped(object sender, EventArgs e) { CheckboxControl.IsChecked = !CheckboxControl.IsChecked; } }
XAML
<?xml version="1.0" encoding="utf-8" ?> <ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Name="ParentControl" x:Class="Temp.CheckMark"> <Grid HorizontalOptions="Fill" BackgroundColor="Transparent" > <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.GestureRecognizers> <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" /> </Grid.GestureRecognizers> <Label Grid.Column="0" Text="{Binding Source={x:Reference ParentControl}, Path=Text}" TextColor="{Binding Source={x:Reference ParentControl}, Path= TextColor, Mode=TwoWay}" FontSize ="{Binding Source={x:Reference ParentControl}, Path= FontSize, Mode=TwoWay}" BackgroundColor="Transparent" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" HorizontalOptions="Fill" /> <CheckBox Grid.Column="0" x:Name="CheckboxControl" Color="{Binding Source={x:Reference ParentControl}, Path=BoxColor, Mode=TwoWay}" BackgroundColor="Transparent" VerticalOptions="Center" HorizontalOptions="End" CheckedChanged="CheckBox_CheckedChanged" /> </Grid> </ContentView> <?xml version="1.0" encoding="utf-8" ?> <ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Name="ParentControl" x:Class="Temp.CheckMark"> <Grid HorizontalOptions="Fill" BackgroundColor="Transparent" > <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.GestureRecognizers> <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" /> </Grid.GestureRecognizers> <Label Grid.Column="0" Text="{Binding Source={x:Reference ParentControl}, Path=Text}" TextColor="{Binding Source={x:Reference ParentControl}, Path= TextColor, Mode=TwoWay}" FontSize ="{Binding Source={x:Reference ParentControl}, Path= FontSize, Mode=TwoWay}" BackgroundColor="Transparent" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" HorizontalOptions="Fill" /> <CheckBox Grid.Column="0" x:Name="CheckboxControl" Color="{Binding Source={x:Reference ParentControl}, Path=BoxColor, Mode=TwoWay}" BackgroundColor="Transparent" VerticalOptions="Center" HorizontalOptions="End" CheckedChanged="CheckBox_CheckedChanged" /> </Grid> </ContentView>
Host Page
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:local="clr-namespace:Temp" x:Class="Temp.MainPage"> <ContentPage.BindingContext> <local:Viewmodel /> </ContentPage.BindingContext> <local:CheckMark Text="{Binding UserName}" SelectionCommand="{Binding MyCommand}" BoxColor ="Black" BackgroundColor ="Pink" SelectedBoxColor ="Yellow" DeselectedBoxColor ="Pink" SelectedTextColor ="White" SelectedBackgroundColor ="Green" DeselectedTextColor ="Black" DeselectedBackgroundColor ="Red" FontSize ="26" WidthRequest ="450" HeightRequest ="100" /> </ContentPage>
Viewmodel
public class Viewmodel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public Viewmodel() { MyCommand = new DelegateCommand(arg => Debug.WriteLine("Hello World")); } public ICommand MyCommand { get; set; } string _username = "default-username"; public string UserName { get { return _username; } set { if (_username != value) { _username = value; OnPropertyChanged(); } } } void OnPropertyChanged([CallerMemberName] string propertyname = "") { PropertyChanged(this, new PropertyChangedEventArgs(propertyname)); } }