Cum să utilizați RX de control-comandă și disponibilitatea în scenarii complexe?

0

Problema

Configurarea

Să presupunem următoarele. Avem un text teoretic viewmodel clasa de aplicație WPF:

public MyViewModel
{

    public MyViewModel()
    {
        // Condition under which this command may be executed is:
        // this.ActiveDocument.Highlighting.Type == Highlighting.Xml && 
        //    !this.ActiveDocument.IsReadOnly && 
        //    (this.License.Kind == LicenseKind.Full || this.License.TrialDay < 30)
        MyCommand = new Command(obj => DoSomething());
    }

    public ICommand MyCommand { get; } 
    // (all other required properties)
}

În plus:

  • Actuala clasă implementează în mod corespunzător INotifyPropertyChanged
  • Toate clasele din statele acces lanțuri pune în aplicare în mod corespunzător INotifyPropertyChanged (de exemplu. document accesibil din viewmodel ActiveDocument de proprietate)
  • ActiveDocument poate fi null. ActiveDocument.Highlighting poate fi, de asemenea, nul.

Problema

Mi-ar place comandă să fie activată numai atunci când starea în comentariu este cunoscut.

Opțiune fără RX

Am scris propria mea bibliotecă pentru a gestiona aceste situații. Soluția ar fi:

public MyViewModel
{
    private readonly Condition commandAvailableCondition;

    public MyViewModel()
    {
        commandAvailableCondition = new LambdaCondition(this, 
            vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && 
                !vm.ActiveDocument.IsReadOnly && 
                (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30),
            false);

        MyCommand = new AppCommand(obj => DoSomething(), commandAvailableCondition);
    }

    public ICommand MyCommand { get; } 
    // (all other required properties)
}

Sau - dacă doriți codul fi un pic mai ușor de citit, așa că parțială condiții ar putea fi refolosite - așa:

public MyViewModel
{
    private readonly Condition commandAvailableCondition;

    public MyViewModel()
    {
        var highlightingIsXml = new LambdaCondition(this, 
            vm => vm.ActiveDocument.Highlighting.Type == Highlighting.Xml, 
            false);
        var documentIsReadonly = new LambdaCondition(this,
            vm => vm.ActiveDocument.IsReadOnly, 
            false);
        var appIsLicensed = new LambdaCondition(this,
            vm => vm.License.Kind == LicenseKind.Full || this.License.TrialDay < 30,
            false);

        commandAvailableCondition = highlightingIsXml & !documentIsReadonly & appIsLicensed;

        MyCommand = new AppCommand(obj => DoSomething(), commandAvailableCondition);
    }

    public ICommand MyCommand { get; } 
    // (all other required properties)
}

Ce biblioteca mea (sau, mai precis, LambdaCondition clasa) nu este:

  • Ea ține evidența tuturor cazuri de punere în aplicare INotifyPropertyChanged și mâner modificări (de exemplu. când ActiveDocument modificări sau ActiveDocument.Highlighting modificări sau ActiveDocument.Highlighting.Type modificări etc.)
  • Ea ține evidența posibil nulle pe drum, caz în care se va returna valoarea implicită (în acest caz, false)
  • Acesta va automat rapoarte de modificări (dar numai modificări) disponibilitatea de a comanda, astfel încât UI pot fi actualizate atunci când este necesar.

Întrebarea

Cum s-ar pune în aplicare scenariul descris mai sus, folosind System.Reactive in C#? Este posibil să se facă cu ușurință păstrând în același timp toate cerințele despre INotifyPropertyChanged, null-uri pe drum și valoarea implicită? S-ar putea face orice sănătoasă ipoteze atunci când este necesar.

c# mvvm system.reactive wpf
2021-11-23 15:15:48
1

Cel mai bun răspuns

0

La ReactiveUI cadru are o ReactiveCommand clasa care foloseste un IObservable<T> pentru a actualiza statutul de comandă (de exemplu, ridica CanExecuteChanged eveniment de ICommand).

Vă rugăm să consultați docs pentru un exemplu de cum să utilizați-l pentru a controla execuție:

var canExecute = this.WhenAnyValue(
    x => x.UserName, x => x.Password,
    (userName, password) => 
        !string.IsNullOrEmpty(userName) && 
        !string.IsNullOrEmpty(password));

var command = ReactiveCommand.CreateFromTask(LogOnAsync, canExecute);
2021-11-24 14:52:33

Nu-l urmeze INotifyPropertyChange implementatori în accesul proprietate lanț? Are, de asemenea, funcționa corect dacă oricare dintre proprietăți este nul? Ai putea, te rog arată, cum mi exemplu concret ar arăta atunci când sunt implementate în RX?
Spook

WhenAnyValue se emite o nouă valoare atunci când oricare dintre Username și Password proprietăți rasises la PropertyChanged eveniment. Ce este exemplu specific, mai exact? Ce ai încerca?
mm8

Mi-ai citit toata intrebarea? Am prezentat starea exactă, care ar trebui să fie privit: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Dacă de exemplu. ActiveDocument este nul? Va RX-l ocupe în mod corespunzător? Mă aștept ca în acest caz condiția să aibă valoarea sa implicită (sau cel puțin false în mod implicit)
Spook

Dacă ActiveDocument, veți obține o NullReferenceException. Acest lucru nu are nimic de-a face cu RX.
mm8

În biblioteca mea nu. Asta e, printre altele, este de ce sunt interesați, dacă RX este bine-potrivite pentru această sarcină.
Spook

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................