Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding views to ICommand.CanExecute

Tags:

mvvmcross

Is it somehow possible to bind view properties to ICommand.CanExecute?

I'd for example like to be able to do something like this in a touch view:

this
    .CreateBinding(SignInWithFacebookButton)
    .For(b => b.Enabled)
    .To((SignInViewModel vm) => vm.SignInWithFacebookCommand.CanExecute)
    .Apply();

I've already read How to use CanExecute with Mvvmcross, but unfortunately it skips the questions and instead just proposes another implementation.

like image 430
Stefan Fisk Avatar asked Jun 06 '26 04:06

Stefan Fisk


1 Answers

One way of doing this is to use your own custom button inheriting from UIButton.

For Android, I've got an implementation of this to hand - it is:

public class FullButton : Button
{
    protected FullButton(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
        Click += OnClick;
    }

    public FullButton(Context context) : base(context)
    {
        Click += OnClick;
    }

    public FullButton(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        Click += OnClick;
    }

    public FullButton(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
    {
        Click += OnClick;
    }

    private IDisposable _subscription;

    private object _commandParameter;
    public object CommandParameter
    {
        get { return _commandParameter; }
        set
        {
            _commandParameter = value;
            UpdateEnabled();
        }
    }

    private ICommand _command;
    public ICommand Command
    {
        get { return _command; }
        set
        {
            if (_subscription != null)
            {
                _subscription.Dispose();
                _subscription = null;
            }

            _command = value;

            if (_command != null)
            {

                var cec = typeof (ICommand).GetEvent("CanExecuteChanged");
                _subscription = cec.WeakSubscribe(_command, (s, e) =>
                    {
                        UpdateEnabled();
                    });
            }

            UpdateEnabled();
        }
    }

    private void OnClick(object sender, EventArgs eventArgs)
    {
        if (Command == null)
            return;

        if (Command.CanExecute(CommandParameter))
            Command.Execute(CommandParameter);
    }

    private void UpdateEnabled()
    {
        Enabled = ShouldBeEnabled();
    }

    private bool ShouldBeEnabled()
    {
        if (_command == null)
            return false;

        return _command.CanExecute(CommandParameter);
    }
}

and this can be bound as:

<FullButton
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Show Detail"
    local:MvxBind="Command ShowDetailCommand; CommandParameter CurrentItem" />

For iOS, I'd expect the same type of technique to work... inheriting from a UIButton and using TouchUpInside instead of Click - but I'm afraid I don't have this code with me at the moment.

like image 200
Stuart Avatar answered Jun 10 '26 09:06

Stuart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!