Gestione dello stato in WPF-MVVM

3

Sto cercando consigli sugli stati di gestione in un ambiente MVVM WPF.

Ad esempio, supponiamo di avere

  • UnTreeView(oqualchealtroItemsControl)conalcunielementie
  • unpulsanteabilitatoquandounelementoèselezionato.

MyViewModelcontieneunaproprietàSelectedItemassociataalSelectedItemdiTreeView.

Quandosifaclicsulpulsante,sipassaa"stato speciale": l'attuale SelectedItem viene memorizzata da qualche parte per un riferimento futuro (chiamiamo la variabile di memorizzazione FirstSelectedItem ). Quindi la selezione viene cancellata, il pulsante è disabilitato e l'utente deve selezionare di nuovo un oggetto (può essere qualsiasi oggetto, anche lo stesso). Quindi otteniamo una voce in SelectedItem . Quindi i dati dell'elemento memorizzato in FirstSelectedItem vengono modificati in base a SelectedItem (modifica alcune proprietà interne che non sono visibili nella vista). Al termine, SelectedItem viene ripristinato per contenere FirstSelectedItem , il pulsante è abilitato e la vista è di nuovo in "stato normale".

Mi piacerebbe sapere come ti avvicini a questi problemi in WPF. Per me è importante usare il pattern MVVM e usare codebehind solo per reindirizzare le cose al ViewModel, e che è possibile dare a ogni elemento dell'interfaccia utente un aspetto e un comportamento diverso a seconda dello stato corrente . In un esempio più complicato, potrebbe essere che alcuni controlli diventino disabilitati o mostrino o eseguano un altro comando del solito quando un determinato stato è attuale.

Per quanto riguarda l'aspetto, penso che un modo sarebbe avere una proprietà State nel ViewModel. Gli elementi dell'interfaccia utente possono quindi in qualche modo rendere il loro aspetto dipendente da quello stato (anche se non so come, ma sono sicuro che sia possibile).

Per il comportamento, non ne ho idea. Per quanto ne so, un pulsante può legarsi a un unico comando e uno solo. Oppure è possibile modificare l'associazione in base a State ?

    
posta Kjara 05.10.2016 - 13:55
fonte

2 risposte

1

Se capisco cosa stai dicendo, hai bisogno di un indizio UI da denotare quando la proprietà State cambia. Ci sono molti modi per farlo in puro MVVM.

Potresti usare un ValueConverter per convertire il valore dello stato in un valore System.Windows.Visibility associato alla visibilità di determinati elementi per facilitare le modifiche alla visibilità in base alla proprietà State . Potresti fare lo stesso con un convertitore per convertire lo stato in booleano allo scopo di facilitare anche IsEnabled o IsReadOnly .

Quindi, se si desidera che il comando del pulsante cambi a seconda dello stato, è possibile modificare l'associazione e aumentare un PropertyChanged sul comando per il pulsante. O semplicemente cambia il metodo sottostante se stai usando qualcosa come RelayCommand visto qui . O potresti semplicemente avere un comando che esegue alcune routine che sono influenzate dalla proprietà State . O magari passare allo stato come parametro di comando.

Potresti anche utilizzare DataTemplates e associare un DataTemplate a la proprietà State .

Facilitare un cambiamento di stato, a seconda di cosa significhi, potrebbe essere la logica aziendale, e probabilmente non dovrebbe andare nel ViewModel (a meno che, come ha detto Rachel, si tratti di un'app molto piccola con un bisogno limitato di astrazione). Tuttavia, ciò che stai tentando di fare con l'interfaccia utente può essere fatto con associazioni e modifiche / notifiche di proprietà ViewModel. Esistono 1.000 modi per dare la pelle a un gatto, devi solo trovare quello più adatto a te.

    
risposta data 09.01.2017 - 00:05
fonte
0

Dalla tua descrizione, sembra che si tratti di business logic, quindi probabilmente lo inserirò nel mio livello ViewModel / Model.

Qualcosa come:

public class MyViewModel()
{
    private object _first
    private object _second;

    // bind TreeView.SelectedItem to this property
    public object SelectedItem
    {
        get { return (_isSecondState ? _second : _first); }
        set 
        {
            // Personally I'd rather try to do this in a PropertyChange event than 
            // a property setter, but this is for simplicity
            if (_isSecondState)
            {
                _second = value;

                // handle whatever should happen when second is clicked
                DoSomething();

                // revert back to first state
                _isSecondState = false;
            }
            else
            {
                _first = value;
            }
        }
    }

    public ICommand MyButtonCommand
    {
        get
        {
            if (_getProductCommand == null)
            {
                _getProductCommand = new RelayCommand(
                    param => ButtonCommand(),  // execute when button clicked
                    param => !_isSecondState   // disable button if second state
                );
            }
            return _getProductCommand;
        }
    }

    private void ButtonCommand()
    {
       // setup second state
        _isSecondState = true;
        _second = null;

        // probably need something like this to requery binding
        OnPropertyChanged("SelectedItem");

        // Do whatever you want to do when button clicked
    }
}

Inoltre sulla tua domanda

As far as I know, a Button can bind to one Command, and only one. Or can the binding be changed depending on State?

Sarebbe facile rendere il comando dei pulsanti diverso in base allo stato in cui si trova ViewModel.

L'idea è che se questa è una logica aziendale, appartiene al livello ViewModel / Model. Se si tratta di una logica generica specifica per la vista che potrebbe applicarsi a qualsiasi Button / TreeList / etc, potresti probabilmente codificare un qualche tipo di comportamento specifico dell'interfaccia utente per esso.

    
risposta data 08.12.2016 - 16:53
fonte

Leggi altre domande sui tag