I have a custom checkbox control that I created with an ICommand property and the corresponding bindable property (my checkbox is a Xamarin.Forms XAML Page), the code is:
CheckBox.xaml
<Image x:Name="imgCheckBox"
WidthRequest="20"
HeightRequest="20"/>
<Label x:Name="lblCheckBox"
TextColor="Black"
VerticalOptions="CenterAndExpand"/>
<TapGestureRecognizer Tapped="OnCheckBoxTapped"/>
CheckBox.xaml.cs
public partial class CheckBox : ContentView
{
private static ImageSource uncheckedImage;
private static ImageSource checkedImage;
public CheckBox()
{
InitializeComponent();
uncheckedImage = ImageSource.FromResource("cbUnchecked.png");
checkedImage = ImageSource.FromResource("cbChecked.png");
imgCheckBox.Source = uncheckedImage;
}
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create<CheckBox, bool>(
checkbox =>
checkbox.IsChecked,
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
CheckBox checkbox = (CheckBox)bindable;
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, newValue);
}
});
public bool IsChecked
{
set { SetValue(IsCheckedProperty, value); }
get { return (bool)GetValue(IsCheckedProperty); }
}
void OnCheckBoxTapped(object sender, EventArgs args)
{
IsChecked = !IsChecked;
if (IsChecked)
{
imgCheckBox.Source = checkedImage;
}
else
{
imgCheckBox.Source = uncheckedImage;
}
}
public static readonly BindableProperty CheckBoxCommandProperty =
BindableProperty.Create<CheckBox, ICommand>(
checkbox =>
checkbox.CheckBoxCommand,
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
CheckBox checkbox = (CheckBox)bindable;
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, checkbox.IsChecked);
}
});
public event EventHandler<bool> CheckedChanged;
public ICommand CheckBoxCommand
{
get { return (ICommand)GetValue(CheckBoxCommandProperty); }
set { SetValue(CheckBoxCommandProperty, value); }
}
}
This checkbox implementation is on another Page called TermsAndConditionsPage, that is also a a Xamarin.Forms XAML Page, the code of the implementation is:
<toolkit:CheckBox Text="{Binding txtCheckBox}"
FontSize="Small"
CheckBoxCommand="{Binding OnCheckBoxTapChanged}"
IsChecked="{Binding IsCheckedChanged, Mode=TwoWay}"/>
<Button Text="Next"
Command="{Binding Next_OnClick}"
IsEnabled="{Binding Next_IsEnabled}"
HorizontalOptions="CenterAndExpand"
Clicked="OnNextClicked"/>
The Code Behind of this page is empty (Constructur with InitializeComponent()). I also have the ViewModel of this page with this code:
TermsAndConditionsViewModel.cs
private string _txtCheckBox;
public string txtCheckBox
{ get { return _txtCheckBox; }
set
{
_txtCheckBox = value;
OnPropertyChanged("txtCheckBox");
}
}
private bool _Next_IsEnabled;
public bool Next_IsEnabled
{
get { return _Next_IsEnabled; }
set
{
_Next_IsEnabled = value;
OnPropertyChanged("Next_IsEnabled");
}
}
private bool _IsCheckedChanged;
public bool IsCheckedChanged
{
get { return _IsCheckedChanged; }
set
{
_IsCheckedChanged = value;
OnPropertyChanged("IsCheckedChanged");
}
}
public ICommand Next_OnClick { get; set; }
public ICommand OnCheckBoxTapChanged { get; set; }
public TermsAndConditionsViewModel()
{
txtCheckBox = "I agree with the terms and conditions";
Next_OnClick = new Command(NextClicked);
OnCheckBoxTapChanged = new Command(CheckBoxTapped);
}
private void CheckBoxTapped()
{
if (IsCheckedChanged)
{ Next_IsEnabled = true; }
else
{ Next_IsEnabled = false; }
}
private void NextClicked()
{ App.Current.MainPage = new Views.HelloWorld(); }
#region INPC
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{ PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
Now, the question time: the problem I'm having is the CheckBoxTapped Command is not working, I mean, it doesn't do anything, although the checkbox image changes every time I touch it, it does not change the Next_IsEnabled property of my button. I'd like to know what I am missing here to make this command work properly.
EDIT
What I'm looking for is a Command that behaves similarly to the one that Buttons have.
Thanks all for your time!
Since the original answer is now obsolete, here is the new method:
using System.Windows.Input;
public partial class MyControlExample : ContentView
{
// BindableProperty implementation
public static readonly BindableProperty CommandProperty =
BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(MyControlExample), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Helper method for invoking commands safely
public static void Execute(ICommand command)
{
if (command == null) return;
if (command.CanExecute(null))
{
command.Execute(null);
}
}
public MyControlExample()
{
InitializeComponent();
}
// this is the command that gets bound by the control in the view
// (ie. a Button, TapRecognizer, or MR.Gestures)
public Command OnTap => new Command(() => Execute(Command));
}