I found a better way to do this which is to create your own. It was really quite simple. Create a cs file in a Resources project (or where ever you want) called CheckBox and paste this code:
namespace Resources.Controls
{
public class Checkbox : Button
{
public Checkbox()
{
base.Image = "Image_Unchecked.png";
base.Clicked += new EventHandler(OnClicked);
base.SizeChanged += new EventHandler(OnSizeChanged);
base.BackgroundColor = Color.Transparent;
base.BorderWidth = 0;
}
private void OnSizeChanged(object sender, EventArgs e)
{
//if (base.Height > 0)
//{
// base.WidthRequest = base.Height;
//}
}
public static BindableProperty CheckedProperty = BindableProperty.Create(
propertyName: "Checked",
returnType: typeof(Boolean?),
declaringType: typeof(Checkbox),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: CheckedValueChanged);
public Boolean? Checked
{
get
{
if (GetValue(CheckedProperty) == null)
{
return null;
}
return (Boolean)GetValue(CheckedProperty);
}
set
{
SetValue(CheckedProperty, value);
OnPropertyChanged();
RaiseCheckedChanged();
}
}
private static void CheckedValueChanged(BindableObject bindable, object oldValue, object newValue)
{
if (newValue != null && (Boolean)newValue == true)
{
((Checkbox)bindable).Image = "Image_Checked.png";
}
else
{
((Checkbox)bindable).Image = "Image_Unchecked.png";
}
}
public event EventHandler CheckedChanged;
private void RaiseCheckedChanged()
{
if (CheckedChanged != null)
CheckedChanged(this, EventArgs.Empty);
}
private Boolean _IsEnabled = true;
public Boolean IsEnabled
{
get
{
return _IsEnabled;
}
set
{
_IsEnabled = value;
OnPropertyChanged();
if (value == true)
{
this.Opacity = 1;
}
else
{
this.Opacity = .5;
}
base.IsEnabled = value;
}
}
public void OnEnabled_Changed()
{
}
public void OnClicked(object sender, EventArgs e)
{
Checked = !Checked;
// Call the base class event invocation method.
//base.Clicked(sender, e);
}
}
}
There is probably a better way to do this but I just added the two images to the appropriate locations in each project (base for UWP, Resources/Drawable for Android).
Then to use it in your Xaml just do something like this (I used a converter bc I was binding to a string value):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Resources.Controls;assembly=Resources"
x:Class="MyNameSpace.CheckBoxExamplePage"
Title=" Hygiene">
<Grid Padding="1">
<ScrollView Padding="4">
<StackLayout>
<StackLayout Orientation="Horizontal">
<controls:Checkbox x:Name="cbHello" Text="Hello CheckBox" Checked="{Binding Path=My.Binding.Path, Converter={StaticResource StringToBoolean}, Mode=TwoWay}" />
</StackLayout>
<StackLayout Orientation="Horizontal" Padding="16,0,0,0">
<controls:Checkbox x:Name="cbDisabled" Text="Disabled Example" IsEnabled="False" Checked="{Binding Path=My.Binding.PathTwo, Converter={StaticResource StringToBoolean}, Mode=TwoWay}" />
</StackLayout>
</StackLayout>
</ScrollView>
</Grid>
</ContentPage>
Note: You must set the BindingContext in your pages cs file for the check to work. So your Pages code behind file should look like this:
namespace MyNameSpace
{
public partial class CheckBoxExamplePage
{
public CheckBoxExamplePage(object MyBindingObject)
{
InitializeComponent();
this.BindingContext = MyBindingObject;
}
}
}
And this is the result!
Hope this helps someone!!
UPDATE:
The following is new code that removes the gray background on disabled and also allows text to wrap if it does not fit on the screen. This uses a ContentView that contains a grid that can expand based on the content.
public class Checkbox : ContentView
{
protected Grid ContentGrid;
protected ContentView ContentContainer;
public Label TextContainer;
protected Image ImageContainer;
public Checkbox()
{
var TapGesture = new TapGestureRecognizer();
TapGesture.Tapped += TapGestureOnTapped;
GestureRecognizers.Add(TapGesture);
ContentGrid = new Grid
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
ContentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(42) });
ContentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
ContentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
ImageContainer = new Image
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
};
ImageContainer.HeightRequest = 42;
ImageContainer.WidthRequest = 42;
ContentGrid.Children.Add(ImageContainer);
ContentContainer = new ContentView
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
Grid.SetColumn(ContentContainer, 1);
TextContainer = new Label
{
TextColor = Color.White,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
ContentContainer.Content = TextContainer;
ContentGrid.Children.Add(ContentContainer);
base.Content = ContentGrid;
this.Image.Source = "Image_Unchecked.png";
this.BackgroundColor = Color.Transparent;
}
public static BindableProperty CheckedProperty = BindableProperty.Create(
propertyName: "Checked",
returnType: typeof(Boolean?),
declaringType: typeof(Checkbox),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: CheckedValueChanged);
public static BindableProperty TextProperty = BindableProperty.Create(
propertyName: "Text",
returnType: typeof(String),
declaringType: typeof(Checkbox),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: TextValueChanged);
public Boolean? Checked
{
get
{
if (GetValue(CheckedProperty) == null)
return null;
return (Boolean)GetValue(CheckedProperty);
}
set
{
SetValue(CheckedProperty, value);
OnPropertyChanged();
RaiseCheckedChanged();
}
}
private static void CheckedValueChanged(BindableObject bindable, object oldValue, object newValue)
{
if (newValue != null && (Boolean)newValue == true)
((Checkbox)bindable).Image.Source = "Image_Checked.png";
else
((Checkbox)bindable).Image.Source = "Image_Unchecked.png";
}
public event EventHandler CheckedChanged;
private void RaiseCheckedChanged()
{
if (CheckedChanged != null)
CheckedChanged(this, EventArgs.Empty);
}
private Boolean _IsEnabled = true;
public Boolean IsEnabled
{
get { return _IsEnabled; }
set
{
_IsEnabled = value;
OnPropertyChanged();
this.Opacity = value ? 1 : .5;
base.IsEnabled = value;
}
}
public event EventHandler Clicked;
private void TapGestureOnTapped(object sender, EventArgs eventArgs)
{
if (IsEnabled)
{
Checked = !Checked;
if (Clicked != null)
Clicked(this, new EventArgs());
}
}
private static void TextValueChanged(BindableObject bindable, object oldValue, object newValue)
{
((Checkbox)bindable).TextContainer.Text = (String)newValue;
}
public event EventHandler TextChanged;
private void RaiseTextChanged()
{
if (TextChanged != null)
TextChanged(this, EventArgs.Empty);
}
public Image Image
{
get { return ImageContainer; }
set { ImageContainer = value; }
}
public String Text
{
get { return (String)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
OnPropertyChanged();
RaiseTextChanged();
}
}
}