MVVM con DI, visualizza la posizione del modello e i dati del servizio condiviso

1

Ho un paio di domande sui modelli di visualizzazione MVVM. Ho 3 modelli di visualizzazione nel mio scenario, che ho messo insieme un esempio più breve di seguito. Stavo cercando una soluzione per 3 viste che funzionasse in combinazione tra loro in una piccola parte di una grande applicazione. Ci sono 3 classi in gioco qui:

ParentViewModel

Rappresenta una vista che presenta una casella combinata con l'origine di MyLookups all'utente per selezionare un valore e archiviarlo in SelectedLookup.

C'è un pulsante che invocherà ShowDialogCommand che mostrerà il DialogVM1 tramite IDialogService.

DialogViewModel

Rappresenta una vista in cui l'utente immetterà alcune informazioni sul campo in NewItemTemplate. Quando fanno clic su OK, la finestra di dialogo si chiuderà e NewItemTemplate viene passato a ChildVM1 chiamando SetSomeInformation.

ChildViewModel

All'interno di ChildViewModel i dati del modello vengono quindi trasformati in un elenco di dati, ma ciò è irrilevante. ChildViewModel fornisce una griglia in cui l'utente può modificare un elenco di SomeData. La ricerca DefaultItem viene popolata da una combo nella griglia la cui origine dati è MyLookups.

IViewModelLocatorService

Questo utilizza il mio contenitore IoC per ottenere l'istanza di visualizzazione. Le viste stesse hanno un numero variabile di dipendenze del servizio. La proposta di IViewModelLocatorService doveva creare la mia istanza di visualizzazione quando ne avevo bisogno. Tuttavia, mentre sto scrivendo questo post, penso che potrei semplicemente iniettare l'istanza della vista nel costruttore ParentViewModel. Tutti i miei modelli di visualizzazione sono registrati nel contenitore IoC.

ILookupService

Il suo scopo è compilare un elenco di elementi che verranno visualizzati come una casella combinata su tutte e 3 le visualizzazioni. FindAll colpisce fondamentalmente il database (chiamando Entity Framework) e popola una nuova lista. Ciò crea ogni volta un nuovo DbContext. Al momento la ricerca non ha la precedenza su Equals, quindi anche se i dati saranno gli stessi in base all'Id, ma x == y sarebbe falso, quindi quando i dati vengono passati, sto lavorando con 3 elenchi diversi.

Attualmente tutti i servizi sono registrati come singleton.

public class ParentViewModel
{
    private readonly ILookupService _lookupService;
    private readonly ISomeService _someService;
    private readonly IViewModelLocatorService _vmLocatorService;
    private readonly IDialogService _dialogService;

    public ParentViewModel(
        ILookupService lookupService,
        ISomeService someService, 
        IViewModelLocatorService vmLocatorService,
        IDialogService dialogService,
        ChildViewModel1 ChildViewModel              // should we inject this?
        )
    {
        ...
        MyLookups = _lookupService.FindAll(); // actually done from a load command but added here for simplicity sake
    }

    public ChildViewModel1 { get; private set; }

    public ObservableCollection<Lookup> MyLookups { get; set; }

    public Lookup SelectedLookup { get; private set; }

    public ICommand ShowDialogCommand => new RelayCommand(
                    execute: () => 
                    {
                        // I want to show DialogViewModel here
                        var dialogVM = new DialogViewModel(...);
                        var dialogVM = _vmLocatorService.NewInstance<DialogViewModel>();
                        dialogVM.DefaultLookup = this.SelectedLookup;

                        _dialogService.Show(dialogVM, this);

                        if (dialogVM.DialogResult == true)
                        {
                            // pass some information to the child VM
                            ChildViewModel1.SetSomeInformation(dialogVM.NewItemTemplate);
                        }
                    },
                    canExecute: () => true);

}

public class ChildViewModel1
{
    private readonly ILookupService _lookupService;

    public ChildViewModel1(ILookupService lookupService)
    {
        ...
        MyLookups = _lookupService.FindAll();
    }

    public void SetSomeInformation(Lookup newLookupSelection)
    {
        ...
    }

    public ObservableCollection<Lookup> MyLookups { get; set; }
}

public class DialogViewModel
{
    private readonly ILookupService _lookupService;
    private readonly ISomeOtherService1 _someOtherService1;
    private readonly ISomeOtherService2 _someOtherService2;

    public DialogViewModel(ILookupService lookupService, ISomeOtherService1 someOtherService1, ISomeOtherService2 someOtherService2)
    {
        ...
        MyLookups = _lookupService.FindAll(); // actually done from a load command but added here for simplicity sake
    }

    public SomeData NewItemTemplate { get; private set; }

    public ObservableCollection<Lookup> MyLookups { get; set; }
}

public class SomeData
{
    public long Id { get; set; }
    public string Name { get; set; }
    public Lookup DefaultItem { get; set; }
    ...
}

Le mie domande sono:

  1. IViewModelLocatorService è un modo ragionevolmente valido per ottenere un'istanza del modello di visualizzazione in un modello di vista o è meglio mantenere esplicita la dipendenza iniettando il modello di vista figlio come dipendenza del costruttore? Ho letto cose su questa pratica negativa in passato, anche se non riesco a trovare nulla dopo una rapida occhiata stasera.

  2. Con ILookupService, ci sono attualmente 3 elenchi diversi, ognuno con praticamente gli stessi dati. C'è un buon modo per fare in modo che le 3 viste utilizzino lo stesso elenco di dati? L'unica idea che ho è di impostare forzatamente la lista su DialogVM e ChildViewModel tramite una proprietà.

posta Andez 28.07.2016 - 22:01
fonte

1 risposta

-1

Cerca sempre di ridurre il carico cognitivo e di consegnare la verifica al compilatore.

In particolare:

  • Evita contenitori IoC e localizzatori di servizio perché spostano gli errori in runtime.
  • Mantieni tutto immutabile perché saprai sempre che i riferimenti di condivisione non arrecano alcun danno.

In pratica:

  1. Inietta tutte le dipendenze usando il puro DI, l'operatore new integrato, che supporta l'analisi statica. A meno che non si abbia a che fare con un'applicazione altamente dinamica (ad esempio supporto plug-in, riconfigurazione del tempo di esecuzione, caricamento a caldo ecc.) O ci sono altre considerazioni sulla configurazione di build o sulla gestione delle dipendenze.

  2. Se i dati sono statici, crea una IProvider con una proprietà di raccolta di sola lettura lazy All popolata una volta da% co_de iniettato%. Quindi iniettare la stessa istanza di ILookupService in tre punti. Se i dati sono dinamici, applica anche link per rendere reattiva la proprietà.

risposta data 29.07.2016 - 13:04
fonte

Leggi altre domande sui tag