Как да използвате CanExecute с Mvvmcross

Имам бутон

<Button 
      android:id="@+id/ButtonConnect"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Disconnect"
      local:MvxBind="{'Click':{'Path':'DisconnectCommand'}}" />

И имам команда за това

public IMvxCommand DisconnectCommand
{
    get
    {
        return new MvxRelayCommand(this.GetService<IConnectionService>().Disconnect);
    }
}

След това искам да активирам/деактивирам DisconnectCommand с помощта на

DisconnectCommand.CanExecute(this.GetService<IConnectionService>().UsbConnected);

Но това очевидно не е наред (не работи), поставих проверката като параметър, но обикновено бих направил

DisconnectCommand.CanExecute = someBool;

Но няма свойство за задаване, така че как да стане това?


person Mech0z    schedule 18.10.2012    source източник
comment
UsbConnected метод ли е или свойство?   -  person Daniel Hilgarth    schedule 18.10.2012


Отговори (2)


За да разберете как да използвате CanExecute, погледнете Silverlight или WPF - там има много блогове, които говорят за това как да използвате ICommand - напр. http://weblogs.asp.net/nmarun/archive/2009/12/02/using-icommand-silverlight-4.aspx или http://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 */;
}

Има обаче един малък проблем....

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'}}" />

Определено можете да твърдите, че подходът CanExecute има предимства - защото запазва логиката на командите в един обект и защото може да се използва за предотвратяване на Execute извиквания, случващи се в рамките на RelayCommand. Ето защо се радвам да се опитам да поправя CanExecute бъгове в mvvmcross обвързвания, когато ги открием.

person Stuart    schedule 18.10.2012
comment
Мисля, че е лоша идея да не използвате вградената функционалност. Вашият подход с булевите стойности добавя доста бъркотия към кодовата база. - person Daniel Hilgarth; 18.10.2012
comment
Да... но не си този, който трябва да напише всички свързвания за MonoDroid и MonoTouch :) - person Stuart; 18.10.2012
comment
Съжалявам, не разбирам този коментар :-) - person Daniel Hilgarth; 18.10.2012
comment
Съжалявам - трябва да знам по-добре, отколкото да правя бързи коментари за StackOverflow. По принцип рамката MvvmCross включва библиотеки за обвързване за iOS и Droid - github.com/slodge/MvvmCross /tree/vnext/Cirrious. Те обхващат много (свойства, команди, влагане, конвертори и т.н.), но имат някои пропуски (непълни impls на CommandParameters, Behaviors и т.н.). Въпреки че тези пропуски съществуват, или някой (обикновено аз) трябва да напише кода, за да ги включи, или потребителите трябва да направят свои собствени заобиколни решения - и това може да причини малко допълнително претрупване на ViewModel. Извинявам се още веднъж за бързия коментар :) - person Stuart; 18.10.2012
comment
Важният момент е, че потребителите могат да споделят своите ViewModel в WP7, Win8, iOS и Droid. странностите на mvvmcross може да добавят малко бъркотия, но е по-добре, отколкото да пишете кода отделно за всяка платформа :) - person Stuart; 18.10.2012
comment
Също така промених отговора си - съгласен съм на 100%, че правенето му с помощта на RaiseCanExecuteChanged е по-добрият подход - но заобиколното решение все още е налице, ако потребителят не иска да поправи грешките или да чака аз да ги поправя. Благодаря и извинявай отново :) - person Stuart; 18.10.2012
comment
Ще използвам заобиколното решение, не съм сигурен, че се чувствам достатъчно компетентен да работя върху изходния код - person Mech0z; 18.10.2012
comment
@Stuart: Чудя се дали все пак бихте препоръчали (както през декември 2014 г.) да използвате отделни булеви свойства IsEnabled спрямо CanExecute()? - person Johannes Rudolph; 11.12.2014
comment
Документация на MvvmCross ›Въпреки това, в MvvmCross това автоматично активиране/деактивиране на свързване не е Понастоящем не се поддържа широко - вместо това се предоставя поддръжка на вторични свойства на свързване - напр. към двойки обвързвания... - person SwiftArchitect; 12.11.2019

За да продължа отговора на Стюарт, лесно е да поддържате и двете 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 { ... }
    }

    ...
person HolySamosa    schedule 23.08.2013