Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an ICommand Bindable property on Xamarin Forms

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!

like image 622
Cesar Tomatis Avatar asked Jul 31 '15 12:07

Cesar Tomatis


People also ask

How do you use bindable property in Xamarin forms?

A bindable property can be created by declaring a public static readonly property of type BindableProperty . The bindable property should be set to the returned value of one of the BindableProperty. Create method overloads.

What is ICommand in Xamarin Forms?

Using a Windows class that implements ICommand allows you to share your ViewModels between Windows applications and Xamarin. Forms applications. If sharing ViewModels between Windows and Xamarin. Forms is not a concern, then you can use the Command or Command<T> class included in Xamarin.

What is attached property in Xamarin forms?

Attached properties enable an object to assign a value for a property that its own class doesn't define.

What is BindableObject in Xamarin forms?

The BindableObject class provides a data storage mechanism that enables the application developer to synchronize data between objects in response to changes, for example, between the View and View Model in the MVVM design pattern. All of the visual elements in the Xamarin.


1 Answers

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));
}
like image 55
MovGP0 Avatar answered Oct 04 '22 13:10

MovGP0