MVVM in un'applicazione simile a Photoshop: quale oggetto ha la responsabilità di comporre il documento?

4

Mi chiedo come si possa architettare un'applicazione come Adobe Photoshop per conformarsi al modello di progettazione di C + M + V + VM, in particolare come gestisci la tela?

Ci sarebbe un sistema Model che rappresenta il documento corrente, con i suoi livelli (ognuno contenente dati grezzi di pixel, potenzialmente gigabyte), effetti applicati ai livelli e altre informazioni sullo stato del documento.

Quindi avresti il ViewModel per la finestra principale che avrebbe child-ViewModels per ogni finestra degli strumenti, oltre a un ViewModel figlio per l'area di disegno principale. La mia domanda riguarda il modo in cui ViewModel rappresenterebbe i dati attuali della tela. È responsabilità della View disegnare sullo schermo i pixel del documento composto (o qualche dispositivo di output virtuale per i test), ma chi ha la responsabilità di comporre il documento? È corretto persino comporre il documento affatto ? - Soprattutto se la Vista è abbastanza avanzata da avere la capacità di farlo da sé, come le viste con accelerazione hardware. Cosa succede se la composizione viene eseguita a livello ViewModel sulla GPU, i dati dovrebbero essere passati di nuovo nella memoria principale e quindi copiati nuovamente nella GPU per la vista: l'ottimizzazione di mantenere i dati nella memoria della GPU non può avvenire perché la vista e ViewModel dovrebbe ignorare l'un l'altro.

Esiste una soluzione a questo problema o sarebbe appropriato un modello di progettazione diverso?

    
posta Dai 09.05.2015 - 05:25
fonte

2 risposte

1

C'è qualcosa che ho dovuto imparare durante la progettazione di software di visualizzazione di immagini / dati medici in WPF / MVVM:

If your domain model deals with visualization, then your ViewModel has to contain visual information.

Elaborerò.

Facciamo un esempio di un sistema di contabilità. Qui è possibile ottenere tutte le funzionalità dell'applicazione nel modello, ma sarebbe strano per un essere umano gestire tutti i concetti contabili senza visualizzarli. Inserisci la vista, puramente come aiuto (una vera e propria interfaccia grafica in un senso di interazione uomo-computer), in modo che l'operatore umano possa vedere lo stato delle informazioni sottostanti, che non ha una visuale stesso.

D'altro canto, prendiamo il tuo esempio estremo: un'applicazione il cui molto utile è quello di manipolare le immagini. Cioè, la classe del modello di dominio principale è l'immagine composita, con i suoi livelli e ognuno con i suoi effetti pixel e le maschere e così via.

Un concetto base di MVVM, Data Binding perde totalmente il suo senso qui: come si suppone di avere una proprietà nel ViewModel, che è legata a una proprietà nella View, se proprio la cosa stai rappresentando è già composto da pixel? Perlomeno, suppongo, il tuo code-behind dovrebbe essere molto ricco (invece di inesistente nel purista MVVM by-the-book).

Quello che sto facendo ultimamente (l'attuale applicazione che sto sviluppando ha un plotter in tempo reale personalizzato) è più o meno così:

  1. Il mio livello di modello è un modello di dominio, contenente solo le classi concettuali relative al problema generale e le regole in base alle quali gli oggetti cooperano tra loro. Niente di correlato all'applicazione (ovvero, che potrebbe variare tra le diverse applicazioni che lavorano sullo stesso dominio) risiede in questo livello, che comunque non contiene l'infrastruttura WPF. I candidati di buona classe sarebbero CompositeCanvas , CanvasLayer , PixelEffect , Mask , Tool , ecc.

  2. Il livello ViewModel contiene la logica dell'applicazione, ovvero come l'applicazione corrente sceglie di manipolare gli oggetti del modello di dominio. Qui iniziamo a usare le classi relative a WPF. Ad esempio, molto probabilmente rappresenterei un CompositeCanvas con un WriteableBitmap , poiché può essere utilizzato direttamente come proprietà Source di un controllo Image tramite il classico binding di dati.

  3. Il livello View sarebbe il più stupido possibile. A prescindere dai controlli di input della pelatura (pulsanti della barra degli strumenti, cursori del mouse personalizzati e manipolatori del manipolatore), l'immagine composita effettiva sarebbe composta da uno o più WriteableBitmaps impilati in un Canvas o Grid o ViewBox (o una combinazione di essi).

Una cosa importante da considerare è il modo in cui gli strati interagiscono tra loro:

  • Se disponi di livelli indipendenti che non interagiscono tra loro, ovvero un'applicazione meno sofisticata di Photoshop, puoi comporli nella vista, impilando più Image i controlli l'uno sull'altro all'interno di una griglia.
    • Ora se vuoi implementare le modalità di fusione , potresti preferire un singolo Image per rappresentare ogni livello e applica la composizione alla sua BitmapSource, che potrebbe essere un DrawingImage con un DrawingGroup contenente più ImageDrawing , uno per ogni livello. Che trasferiscono il compositing al ViewModel.
    • Ora se si desidera controllo completo , in modo da poter applicare sofisticati algoritmi di elaborazione delle immagini, rappresentare l'immagine come array (di doppio, sarebbe una buona cosa), cambiare le modalità colore e fai altre cose intelligenti, allora potresti perfettamente avere i tuoi livelli rappresentati nel modello, e avere qualche operazione per, per esempio, trasferire quell'array a un WriteableBitmap nel ViewModel, che quindi aggiorna automaticamente l'immagine della vista.

È interessante "visualizzare" (il gioco di parole) come, ad esempio, il disegno con una matita levigata e autolivellante funzionerebbe: con lo strumento selezionato, si fa clic sull'immagine e si trascina. È possibile implementare DataContext (ViewModel) come interfaccia, ad esempio ITool e creare eventi del mouse come i metodi di chiamata MouseMove sul ViewModel. Dovresti quindi memorizzare le coordinate dello spazio di disegno (non lo spazio dello schermo) in una matrice, che potrebbe essere continuamente livellata da un algoritmo definito nel modello. Quindi, puoi rigenerare l'origine dell'immagine (cioè render nel modello), e nel ViewModel hai appena impostato il suo risultato sulla proprietà CanvasSource , e l'evento modificato della proprietà si aggiornava automaticamente la vista. Questo è molto diverso dalla maggior parte delle demo di disegno del mouse trovate usando WPF.

Spero che questo aiuti!

    
risposta data 08.08.2015 - 05:04
fonte
0

Mi sembra un problema con il modello viewmodel. In WPF (il framework MVVM con cui ho più familiarità), la vista gestisce tutto ciò che riguarda il rendering e la composizione degli elementi di visualizzazione in un modo agnostico di dominio. Sa come eseguire il rendering di una casella di testo o tracciare una linea su una tela, ma non sa che questa linea proviene dal livello 1 del mio documento. Conosce molti modi per disegnare linee, ma non sa nulla del perché. Non sa ad esempio che la linea 1 è collegata alla linea 2 e quando sposto la linea 1, la linea 2 dovrebbe venire con essa.

Quindi nel tuo esempio, tutto ciò che riguarda il rendering finale del documento è ovviamente la vista. Tutte le informazioni del dominio (livelli, effetti applicati, ecc.) Sono il modello. E tutto il resto - tutto il codice dell'adattatore per piegare il tuo modello per adattarsi a una vista particolare - è il viewmodel. Il viewmodel si occupa di: come preparare il mio modello a essere utilizzato dalla vista e come reagire agli eventi dalla vista.

    
risposta data 10.05.2015 - 02:43
fonte

Leggi altre domande sui tag