如何在Mvvmcross中使用CanExecute

Mec*_*h0z 8 c# data-binding xamarin.android mvvmcross

我有一个按钮

<Button 
      android:id="@+id/ButtonConnect"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Disconnect"
      local:MvxBind="{'Click':{'Path':'DisconnectCommand'}}" />
Run Code Online (Sandbox Code Playgroud)

我有一个命令

public IMvxCommand DisconnectCommand
{
    get
    {
        return new MvxRelayCommand(this.GetService<IConnectionService>().Disconnect);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我想使用启用/禁用DisconnectCommand

DisconnectCommand.CanExecute(this.GetService<IConnectionService>().UsbConnected);
Run Code Online (Sandbox Code Playgroud)

但这显然是错误的(它不起作用),我把检查作为一个参数,但通常我会这样做

DisconnectCommand.CanExecute = someBool;
Run Code Online (Sandbox Code Playgroud)

但是没有设置属性,所以如何去做呢?

Stu*_*art 7

要了解如何使用CanExecute,请查看Silverlight或WPF - 那里有很多关于如何使用的博客ICommand- 例如http://weblogs.asp.net/nmarun/archive/2009/12/02/using -icommand-silverlight-4.aspxhttp://blog.galasoft.ch/archive/2009/09/26/using-relaycommands-in-silverlight-and-wpf.aspx

一个例子是:

private MvxRelayCommand _disconnectCommand;
public IMvxCommand DisconnectCommand
{
    get
    {
        if (_disconnectCommand == null)
            _disconnectCommand = new MvxRelayCommand(this.GetService<IConnectionService>().Disconnect, item => this.IsItemConnected(item));
        return _disconnectCommand;
    }
}

private void SomeServiceNotificationHandler()
{
    _disconnectCommand.RaisePropertyChanged();
}

private bool IsItemConnected(object thing)
{
    return /* your code */;
}
Run Code Online (Sandbox Code Playgroud)

虽然有一个小问题....

CanExecute在所有平台上的所有MvxBindings中并没有真正完全实现......它将适用于其中一些,但对于其中一些它不会 - 我目前还不知道哪些!如果您遇到问题,请告诉我(通过GitHub问题),他们将得到修复......


个人...我不倾向于使用CanExecute-我倾向于而是使用一个单独的布尔属性,然后我绑定到任何财产可在控制-例如,大多数控件有这样的事Enabled,IsEnabled,Disabled,IsDisabled,等.

我通常发现设置布尔属性而不是调用更容易(也更可读) RaiseCanExecuteChanged

例如,我会使用类似的东西:

<Button 
  android:id="@+id/ButtonConnect"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="Disconnect"
  local:MvxBind="{'Click':{'Path':'DisconnectCommand'},'Enabled':{'Path':'UsbConnected'}}" />
Run Code Online (Sandbox Code Playgroud)

你肯定可以说这种CanExecute方法有优点 - 因为它将Command逻辑保存在一个对象中,并且因为它可以用来防止在一个对象中发生的Execute调用RelayCommand.这就是为什么我很乐意尝试修复CanExecutemvvmcross绑定中的错误.

  • @Stuart:我想知道你是否仍然(如2014年12月)建议使用单独的IsEnabled布尔属性与CanExecute()? (5认同)
  • 是的......但你不是必须为MonoDroid和MonoTouch编写所有绑定的人:) (2认同)
  • 重要的是,用户可以在WP7,Win8,iOS和Droid之间共享他们的ViewModel.mvvmcross怪癖可能会增加一点点混乱,但它比为每个平台单独编写代码要好:) (2认同)

Hol*_*osa 5

要跟进 Stuart 的回答,很容易同时支持两者ICommand.CanExecute以及公开属性以支持 Android 和 iOS Mvx 绑定。

为此,请将典型的CanExecute() 方法转换为属性,然后将处理程序添加到对关联属性的CanExecuteChanged调用RaisePropertyChanged。然后RaiseCanExecuteChanged正常使用,PropertyChanged事件也会被触发。

    ...

    // constructor
    public SomeClass()
    {

        DoSomethingCommand = new MvxCommand(OnDoSomething, () => CanDoSomething);
        DoSomethingCommand .CanExecuteChanged += (sender, args) => RaisePropertyChanged(() => CanDoSomething);
    }

    public bool CanDoSomething
    {
        get { ... }
    }

    ...
Run Code Online (Sandbox Code Playgroud)