Come utilizzare RX di controllo del comando di disponibilità in scenari complessi?

0

Domanda

Il programma di installazione

Si ipotizzi il seguente. Abbiamo il seguente teorico classe viewmodel per applicazione 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)
}

Inoltre:

  • Classe implementa correttamente INotifyPropertyChanged
  • Tutte le classi di accesso ai membri delle catene implementa correttamente INotifyPropertyChanged (es. documento viewmodel accessibile da ActiveDocument la struttura)
  • ActiveDocument può essere null. ActiveDocument.Highlighting può anche essere null.

Il problema

Vorrei il comando per essere attivata solo quando la condizione in commento è soddisfatta.

Opzione senza RX

Ho scritto la mia libreria per la gestione di tali situazioni. La soluzione potrebbe essere:

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

O - se si desidera che il codice di essere un po ' più leggibile, in modo parziale le condizioni potrebbero essere riutilizzati come che:

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

Quello che la mia libreria (o, più precisamente, LambdaCondition classe) è:

  • Esso tiene traccia di tutte le istanze di attuazione INotifyPropertyChanged e gestire i cambiamenti (es. quando ActiveDocument modifiche o ActiveDocument.Highlighting modifiche o ActiveDocument.Highlighting.Type modifiche etc.)
  • Esso tiene traccia di possibili nulls sul modo in cui il caso verrà restituito il valore di default (in questo caso, false)
  • Automaticamente i rapporti di modifiche (ma cambia solo) di disponibilità a comando, in modo che l'interfaccia utente può essere aggiornata quando necessario.

La domanda

Come implementare lo scenario sopra descritto utilizzando System.Reactive in C#? È possibile farlo facilmente, mantenendo tutte le esigenze INotifyPropertyChangedi valori null e sul modo in cui il valore di default? Si può fare qualsiasi sano di mente ipotesi, quando necessario.

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

Migliore risposta

0

Il ReactiveUI quadro ha un ReactiveCommand classe che utilizza un IObservable<T> per aggiornare lo stato del comando (cioè aumentare il CanExecuteChanged caso di ICommand).

Si prega di fare riferimento ai documenti per un esempio di come usarlo per controllare executability:

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

Non seguire INotifyPropertyChange implementatori nell'accesso alla proprietà della catena? Lo fa anche a funzionare correttamente se uno qualsiasi di proprietà è null? Si potrebbe si prega di mostrare, come il mio esempio specifico sarebbe se attuate in RX?
Spook

WhenAnyValue creare un nuovo valore quando uno dei Username e Password proprietà rasises il PropertyChanged evento. Qual è il tuo esempio specifico esattamente? Che cosa hai provato?
mm8

Hai letto tutta la mia domanda? Ho presentato l'esatta condizione, che dovrebbe essere guardato: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Che cosa succede se, ad esempio. ActiveDocument è nullo? Sarà RX gestire correttamente? Mi aspetto che in questo caso la condizione per avere il suo valore di default (o almeno false per impostazione predefinita)
Spook

Se ActiveDocumentsi otterrà un NullReferenceException. Questo non ha nulla a che fare con RX.
mm8

Nella mia libreria non voglio. Che, tra l'altro, è il motivo per cui sono interessato, se la RX è il più adatto per questo compito.
Spook

In altre lingue

Questa pagina è in altre lingue

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