Como usar RX para comando de controle de disponibilidade em cenários complexos?

0

Pergunta

O programa de configuração

Vamos supor o seguinte. Temos o seguinte teórico classe viewmodel para aplicação 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)
}

Além disso:

  • Atual classe implementa corretamente INotifyPropertyChanged
  • Todas as classes no acesso ao portal cadeias implementa corretamente INotifyPropertyChanged (por exemplo. documento viewmodel acessível a partir de ActiveDocument propriedade)
  • ActiveDocument pode ser null. ActiveDocument.Highlighting também pode ser nulo.

O problema

Eu gostaria que o comando seja ativado apenas quando a condição comentário é atendida.

Opção sem RX

Eu escrevi a minha própria biblioteca para manipulação de tais situações. A solução seria:

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 - se você quer que o código a ser um pouco mais legível, para que parcial, as condições poderiam ser reutilizados, como:

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

O que a minha biblioteca (ou, mais precisamente, LambdaCondition classe) faz é:

  • Ele mantém o controle de todas as instâncias de execução INotifyPropertyChanged e lidar com mudanças (por exemplo. quando ActiveDocument alterações ou ActiveDocument.Highlighting alterações ou ActiveDocument.Highlighting.Type alterações etc.)
  • Ele mantém o controle de possíveis nulls no caminho, caso em que será retornar ao valor padrão (neste caso, false)
  • Ele será automaticamente relatórios de alterações (mas apenas alterações) de disponibilidade para o comando, de modo que a INTERFACE do usuário pode ser atualizada quando necessário.

A pergunta

Como seria de se implementar o cenário descrito acima, usando o System.Reactive em C#? É possível fazê-lo facilmente, mantendo todos os requisitos de cerca de INotifyPropertyChanged, nulos sobre a forma e o valor padrão? Você pode fazer qualquer sã pressupostos, quando necessário.

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

Melhor resposta

0

O ReactiveUI quadro tem um ReactiveCommand classe que usa um IObservable<T> para atualizar o status do comando (por exemplo, aumentar o CanExecuteChanged evento do ICommand).

Por favor, consulte os documentos para obter um exemplo de como usá-lo para controlar a exequibilidade:

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

Não siga INotifyPropertyChange implementadores no acesso à propriedade de cadeia? Ele também funcionar corretamente se qualquer uma das propriedades é nulo? Por favor, você poderia mostrar, como o meu exemplo seria quando implementado no RX?
Spook

WhenAnyValue emitir um novo valor quando qualquer uma das Username e Password propriedades rasises o PropertyChanged do evento. Qual é o seu exemplo específico, exatamente? O que você fez?
mm8

Você leu toda a minha pergunta? Apresentei a condição exata, que é suposto para ser visto: vm => m.ActiveDocument.Highlighting.Type == Highlighting.Xml && !vm.ActiveDocument.IsReadOnly && (vm.License.Kind == LicenseKind.Full || vm.License.TrialDay < 30), O que se eg. ActiveDocument é nulo? Vai RX lidar com isso corretamente? Espero que, neste caso, a condição de ter seu valor padrão (ou, pelo menos, falso por padrão)
Spook

Se ActiveDocument, você vai ter um NullReferenceException. Isso não tem nada a ver com RX.
mm8

Em minha biblioteca, eu não. Que, entre outros, é por isso que eu estou interessado, se o RX é bem adequado para esta tarefa.
Spook

Em outros idiomas

Esta página está em outros idiomas

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