Comment utiliser RX pour le contrôle de la commande à la disponibilité dans des scénarios complexes?

0

La question

Le programme d'installation

Supposons ce qui suit. Nous avons un théorique classe viewmodel pour application 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)
}

En outre:

  • Actuelle classe implémente correctement INotifyPropertyChanged
  • Toutes les classes dans l'accès des membres des chaînes implémente correctement INotifyPropertyChanged (eg. document viewmodel accessible à partir de ActiveDocument de la propriété)
  • ActiveDocument peut-être null. ActiveDocument.Highlighting peut également être null.

Le problème

J'aimerais que la commande doit être activée uniquement lorsque la condition de commentaire est rencontré.

Option sans RX

J'ai écrit ma propre bibliothèque pour la manipulation de telles situations. La solution serait soit:

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

Ou - si vous voulez que le code soit un peu plus lisible, de sorte que partielle, les conditions pourraient être réutilisés, comme ç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 que ma bibliothèque (ou, plus précisément, LambdaCondition de classe) est la suivante:

  • Il garde la trace de toutes les instances de mise en œuvre INotifyPropertyChanged et de gérer les changements (par exemple. lorsque ActiveDocument des modifications ou des ActiveDocument.Highlighting des modifications ou des ActiveDocument.Highlighting.Type etc.)
  • Il garde la trace de possible nulls sur la façon dont les cas, il sera de retour la valeur par défaut (dans ce cas, false)
  • Il sera automatiquement des rapports de changements (changements seulement) de la disponibilité à la commande, de sorte que l'INTERFACE utilisateur peut être actualisée en cas de besoin.

La question

Comment mettre en œuvre le scénario décrit ci-dessus à l'aide de System.Reactive en C#? Est-il possible de le faire facilement tout en gardant toutes les exigences en ce qui concerne INotifyPropertyChanged, les valeurs null sur le moyen et la valeur par défaut? Vous pouvez faire tous les sane hypothèses en cas de besoin.

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

La meilleure réponse

0

Le ReactiveUI cadre a un ReactiveCommand la classe qui utilise une IObservable<T> pour actualiser l'état de la commande (c'est à dire augmenter le CanExecuteChanged cas de la ICommand).

Veuillez consulter les docs pour un exemple de comment l'utiliser pour contrôler 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

Est-ce INotifyPropertyChange maîtres d'œuvre dans l'accès à la propriété de la chaîne? Est-il aussi fonctionner correctement si l'une des propriétés est null? Pourriez-vous s'il vous plaît montrer, comment mon exemple précis regarder lors de la mise en œuvre de RX?
Spook

WhenAnyValue émet une nouvelle valeur lorsque l'un des Username et Password propriétés rasises l' PropertyChanged de l'événement. Qu'est-ce que votre exemple exactement? Qu'avez-vous essayer?
mm8

Avez-vous lu ma question? J'ai présenté le même état, qui est censé être regardé: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Si par exemple. ActiveDocument est nulle? Va RX gérer correctement? J'attends dans ce cas, la condition de sa valeur par défaut (ou au moins false par défaut)
Spook

Si ActiveDocument, vous obtiendrez un NullReferenceException. Cela n'a rien à voir avec RX.
mm8

Dans ma bibliothèque, je ne veux pas. C'est, entre autres, est pourquoi je suis intéressé, si RX est bien adapté pour cette tâche.
Spook

Dans d'autres langues

Cette page est dans d'autres langues

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