Cómo utilizar RX para el control del comando de la disponibilidad en el complejo de los escenarios?

0

Pregunta

El programa de instalación

Supongamos el siguiente. Tenemos una siguiente teórica clase viewmodel para la aplicación de 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)
}

Además:

  • Actual clase implementa correctamente INotifyPropertyChanged
  • Todas las clases de acceso de los miembros de las cadenas implementa correctamente INotifyPropertyChanged (por ejemplo. documento viewmodel accesible desde ActiveDocument de la propiedad)
  • ActiveDocument puede ser null. ActiveDocument.Highlighting también puede ser null.

El problema

Me gustaría que el comando se activa sólo cuando la condición en el comentario se cumple.

Opción sin RX

Escribí mi propia biblioteca para el manejo de tales situaciones. La solución sería:

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 - si desea que el código sea un poco más fácil de leer, así que parcial de las condiciones podrían ser reutilizados, como que:

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

Lo que mi biblioteca (o, más precisamente, LambdaCondition clase) es:

  • Mantiene un registro de todas las instancias de la aplicación INotifyPropertyChanged y manejar los cambios (por ejemplo. cuando ActiveDocument los cambios o ActiveDocument.Highlighting los cambios o ActiveDocument.Highlighting.Type cambios etc.)
  • Realiza un seguimiento de los posibles nulls en el camino, en cuyo caso se devolverá el valor por defecto (en este caso, false)
  • Se le informa automáticamente de los cambios (pero sólo a los cambios) de la disponibilidad para el comando, por lo que la interfaz de usuario puede ser actualizada cuando sea necesario.

La pregunta

La manera de implementar el escenario descrito anteriormente, utilizando System.Reactive en C#? Es posible hacerlo fácilmente, manteniendo todos los requisitos sobre INotifyPropertyChanged, los valores nulos en el camino, y el valor predeterminado? Usted puede hacer cualquier cuerdo supuestos cuando sea necesario.

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

Mejor respuesta

0

El ReactiveUI marco, tiene un ReactiveCommand clase que utiliza un IObservable<T> para actualizar el estado de la orden (es decir, elevar el CanExecuteChanged evento de la ICommand).

Por favor, consulte el docs para un ejemplo de cómo usar el control de la ejecutabilidad:

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

¿Sigue INotifyPropertyChange implementadores en el acceso a la propiedad de la cadena? ¿También funciona correctamente si alguna de las propiedades es null? Podría usted por favor, mostrar, cómo mi ejemplo sería cuando se implementa en RX?
Spook

WhenAnyValue emitir un nuevo valor cuando cualquiera de los Username y Password propiedades rasises la PropertyChanged evento. ¿Cuál es su ejemplo específico exactamente? ¿Qué intenta?
mm8

Has leído toda mi pregunta? He presentado la condición exacta, que se supone para ser visto: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Lo que si, por ejemplo. ActiveDocument es null? Se RX manejan adecuadamente? Espero que en este caso la condición de que su valor por defecto (o, al menos, false de forma predeterminada)
Spook

Si ActiveDocumentusted obtendrá una NullReferenceException. Esto no tiene nada que ver con RX.
mm8

En mi biblioteca no voy. Ese es, entre otros, es por eso que estoy interesado, si la RX es muy adecuado para esta tarea.
Spook

En otros idiomas

Esta página está en otros idiomas

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