Jak používat RX pro řízení a zabezpečení dostupnosti ve složitých situacích?

0

Otázka

Nastavení

Předpokládejme, že následující. Máme následující teoretické viewmodel třídy pro WPF aplikace:

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)
}

Kromě toho:

  • Aktuální třída implementuje správně INotifyPropertyChanged
  • Všechny třídy v členských přístup řetězy implementuje správně INotifyPropertyChanged (např. dokument viewmodel přístupné z ActiveDocument majetku)
  • ActiveDocument může být null. ActiveDocument.Highlighting může být také null.

Problém

Rád bych příkaz, který má být povolena pouze tehdy, když stav, v komentáři je splněna.

Možnost bez RX

Napsal jsem můj vlastní knihovny pro zpracování takových situací. Řešením by mohlo být buď:

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)
}

Nebo - pokud chcete kód být trochu čitelnější, a to tak, že dílčí podmínky by mohly být znovu použity - jako, že:

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)
}

Co je moje knihovna (nebo, přesněji řečeno, LambdaCondition třídy) je:

  • To udržuje všechny instance provádění INotifyPropertyChanged a zpracovávat změny (např. když ActiveDocument změny nebo ActiveDocument.Highlighting změny nebo ActiveDocument.Highlighting.Type změny atd.)
  • To udržuje, je to možné nulls cestou v takovém případě vrátí výchozí hodnotu (v tomto případě, false)
  • To bude automaticky hlásí změny (ale pouze změny) dostupnost příkazu, tak, že uživatelské ROZHRANÍ může být aktualizován v případě potřeby.

Otázka

Jak by se dalo realizovat scénář je popsáno výše, pomocí System.Reactive v C#? Je možné to udělat snadno při zachování všech požadavků o INotifyPropertyChanged, hodnoty null a výchozí hodnota? Můžete si vytvořit nějaký rozumný předpoklady v případě potřeby.

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

Nejlepší odpověď

0

Na ReactiveUI rámec má ReactiveCommand třída, která používá IObservable<T> aktualizovat stav příkazu (tj. zvýšit CanExecuteChanged událost ICommand).

Prosím, viz docs pro příklad, jak ji použít k ovládání spustitelnost:

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

To neznamená, INotifyPropertyChange realizátoři v majetku přístup řetěz? To je také správně fungovat, pokud některý z vlastností je null? Mohl byste prosím ukázat, jak se můj konkrétní příklad by vypadat, když realizován v RX?
Spook

WhenAnyValue se vydávají nové hodnoty, kdy každý z Username a Password vlastnosti rasises na PropertyChanged akce. Jaký je váš konkrétní příklad přesně? Co jste to zkusit?
mm8

Četl jsi celý můj dotaz? Předložil jsem přesně stav, který má být sledován: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Co když např. ActiveDocument je null? Bude RX ní zacházet správně? Očekávám, že v tomto případě je podmínkou, aby jeho výchozí hodnota (nebo alespoň false ve výchozím nastavení)
Spook

Pokud ActiveDocumentdostanete NullReferenceException. To nemá nic společného s RX.
mm8

V mé knihovně nebudu. To je mimo jiné důvod, proč mě to zajímá, zda RX je dobře-vhodný pro tento úkol.
Spook

V jiných jazycích

Tato stránka je v jiných jazycích

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