I have a checkbox that's supposed to fire the IsEnabled event of a button. But somehow the command that's supposed to do that never gets properly binded and therefore executed.
This is the bindable property in CheckBox.xaml.cs (the control):
public static readonly BindableProperty CheckBoxCommandProperty =
BindableProperty.Create<CheckBox, ICommand>(
checkbox =>
checkbox.CheckBoxCommand,
null,
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); }
}
And this is what I have on the ViewModel:
public ICommand Next_OnClick { get; set; }
public ICommand OnCheckBoxTapChanged { get; set; }
public TermsAndConditionsViewModel()
{
Next_OnClick = new Command(NextClicked);
OnCheckBoxTapChanged = new Command(CheckBoxTapped);
}
private void CheckBoxTapped()
{
if (IsCheckedChanged)
{
Next_IsEnabled = true;
}
else
{
Next_IsEnabled = false;
}
}
The CheckBoxTapped method never gets executed and therefore the button property I wanna set never changes.
Thanks in advance folks!
What you can do is to divide the solution of this problem into several levels:
First, create a bindable property for the checkbox and call it is Checked.
I have written a snippit for it but did not really compile it so you might want to modify it if it did not work
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create<CheckBox, bool> (w => w.IsChecked, false);
public bool IsChecked{
get { return GetValue (FooProperty); }
set { SetValue (FooProperty, value); }
}
Second, in the view model make a bool property that has a change notification
private bool _isChecked;
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}
Third, bind your bindable property of the check box "isChecked" to the one in the view model in your xaml:
<StackLayout>
<Checkbox IsChecked = "{Binding IsChecked}"/>
</StackLayout>
Fourth, Buttons in Xaml with MVVM are bound to commands. and in these commands there is a bool property for them that represents "CanExecute" which basically enables or disables the button. so what you have to do in the Xaml is to bind the command of the button to the command in the View Model (lets call it ClickCommand). And ClickCommand's CanExecute actually is just a method that returns the value of "IsChecked".
This will make us modify the setter of the "IsChecked" property so every time it changes it should notify the command to check the CanExecute property.
So the final code will be something like
public TermsAndConditionsViewModel()
{
NextCommand = new Command(ExecuteNextCommand,CanExecuteNextCommand);
OnCheckBoxTapChanged = new Command(CheckBoxTapped);
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked;}
set
{
_isChecked = value;
NextCommand.ChangeCanExecute(); //this will actually notify the command to enable/disable
RaisePropertyChanged("IsChecked");
}
}
public Command NextCommand {get;set;} // this type is available in Xamarin.Forms library
private bool CanExecuteNextCommand()
{
return IsChecked;
}
private void ExecuteNextCommand()
{
// your execution when the button is pressed
}
And the Xaml will be like
<StackLayout>
<Checkbox IsChecked = "{Binding IsChecked}"/>
<Button Text= "Next" Command = "{Binding NextCommand}"/>
</StackLayout>
Solved it using Xamarin.Forms.Behavior. It allows multiple bindings to controls.
For example>
<Entry Placeholder="Enter password"
Text= "{Binding TxtFirstPasswordInput}"
IsPassword="true">
<b:Interaction.Behaviors>
<b:BehaviorCollection>
<b:EventToCommand EventName="Unfocused" Command="{Binding entry_Finished}"/>
<b:EventToCommand EventName="Focused" Command="{Binding entry_Focused}"/>
</b:BehaviorCollection>
</b:Interaction.Behaviors>
</Entry>
And on the ViewModel>
public PasswordInputViewModel()
{
entry_Finished = new Command(validateAndContinue);//unfocused
entry_Focused = new Command(entryFocused); //focused
}