Jak korzystać z RX do zarządzania dostępnością zespołów w trudnych sytuacjach?

0

Pytanie

Konfiguracja

Załóżmy następujący. Mamy następujący teoretyczny klasa viewmodel dla aplikacji 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)
}

W dodatku:

  • Aktualny klasa realizuje poprawnie INotifyPropertyChanged
  • Wszystkie klasy w łańcuchu dostępu uczestników są realizowane zgodnie z oczekiwaniami INotifyPropertyChanged (na przykład, model prezentacji dokumentu, dostępny z ActiveDocument intelektualna)
  • ActiveDocument może być null. ActiveDocument.Highlighting również może być zerowa.

Problem

Chciałbym, aby drużyna była włączona tylko w przypadku spełnienia określonych warunków w komentarzu.

Opcja bez RX

Napisałem własną bibliotekę do obsługi takich sytuacji. Rozwiązaniem byłoby albo:

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

Lub - jeśli chcesz, aby kod był trochę bardziej czytelny, aby częściowe warunki można było użyć ponownie - tak:

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

Że moja biblioteka (lub, dokładniej LambdaCondition klasa) sprawia, że jest to:

  • Śledzi wszystkie wystąpienia, które implementują INotifyPropertyChanged i przetwarzać zmiany (na przykład. kiedy ActiveDocument zmiany lub ActiveDocument.Highlighting zmiany lub ActiveDocument.Highlighting.Type zmiany itp.)
  • Śledzi możliwe nulls w drodze, i w tym przypadku zwróci wartość domyślna (w tym przypadku, false)
  • Automatycznie informuje zespół o zmianach (ale tylko o zmianach) dostępności, aby w razie potrzeby można było zaktualizować interfejs użytkownika.

Pytanie

Jak można było zrealizować scenariusz opisany powyżej, przy użyciu System.Reactive w C#? Czy można to zrobić łatwo, zachowując wszystkie wymagania INotifyPropertyChanged, zera na drodze i wartość domyślna? Można robić wszelkie uzasadnione przypuszczenia, gdy jest to konieczne.

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

Najlepsza odpowiedź

0

Struktura ReactiveUI ma ReactiveCommand klasa, która wykorzystuje IObservable<T> aby zaktualizować status drużyny (czyli podnieść CanExecuteChanged zdarzenie w ICommand).

Proszę odnieść się do dokumentów, dla przykładu na to, jak wykorzystać go do sterowania исполняемостью:

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

Czy to za twórców INotifyPropertyChange w łańcuchu dostępu do właściwości? Czy to działa również poprawnie, jeśli którekolwiek z właściwości jest równa zero? Nie mógłbyś, proszę, pokaż, jak będzie wyglądać mój konkretny przykład przy realizacji w RX?
Spook

WhenAnyValue naprawdę wydaje nową wartość, gdy każdy z Username i Password właściwości charakteryzuje PropertyChanged zdarzenie. Jaki jest dokładnie twój konkretny przykład? Co próbowałeś?
mm8

Przeczytałeś cały mój problem w całości? I przedstawił dokładny warunek, o którym zakłada się śledzić: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), Co, jeśli, na przykład. ActiveDocument jest równa zero? Poradzi sobie, czy RX z tym prawidłowo? Spodziewam się, że w tym przypadku warunek będzie miał wartość domyślna (lub, co najmniej, wartość domyślnie wartość false).
Spook

Jeśli ActiveDocumentdostaniesz NullReferenceExceptionTo nie ma nic wspólnego z RX.
mm8

W mojej bibliotece nie zrobię tego. Oto, między innymi, dlaczego mnie interesuje, czy dobrze RX nadaje się do tego zadania.
Spook

W innych językach

Ta strona jest w innych językach

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