Binding views to ICommand.CanExecute

2019-02-24 14:00发布

问题:

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.

回答1:

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.



标签: mvvmcross