mvvmIniziare con mvvm


Osservazioni

Questa sezione fornisce una panoramica di cosa è mvvm e perché uno sviluppatore potrebbe volerlo utilizzare.

Dovrebbe anche menzionare qualsiasi argomento di grandi dimensioni all'interno di mvvm e collegarsi agli argomenti correlati. Poiché la documentazione di mvvm è nuova, potrebbe essere necessario creare versioni iniziali di tali argomenti correlati.

C # MVVM Riepilogo ed esempio completo

Sommario:

MVVM è un pattern architettonico rappresentato da tre componenti distinti: Model , View e ViewModel . Per comprendere questi tre livelli, è necessario definire brevemente ciascuno di essi, seguito da una spiegazione di come essi lavorano insieme.

Il modello è il livello che guida la logica aziendale. Recupera e archivia le informazioni da qualsiasi fonte di dati per il consumo da ViewModel .

ViewModel è il livello che funge da ponte tra la vista e il modello . Può o non può trasformare i dati grezzi dal modello in una forma presentabile per la vista . Una trasformazione di esempio potrebbe essere: un flag booleano dal modello alla stringa di "True" o "False" per la vista.

View è il layer che rappresenta l'interfaccia del software (ovvero la GUI). Il suo ruolo è quello di visualizzare le informazioni dal ViewModel per l'utente, e di comunicare i cambiamenti delle informazioni al ViewModel.

Questi tre componenti lavorano insieme facendo riferimento l'un l'altro nel modo seguente:

  • La vista fa riferimento a ViewModel .
  • ViewModel fa riferimento al modello .

È importante notare che View e ViewModel sono in grado di comunicazioni bidirezionali conosciute come Data Bindings .

Un ingrediente importante per la comunicazione bidirezionale (associazione dati) è l'interfaccia INotifyPropertyChanged .

Utilizzando questo meccanismo, la vista può modificare i dati nel ViewModel tramite l'input dell'utente e ViewModel può aggiornare la vista con dati che potrebbero essere stati aggiornati tramite processi nel modello o con dati aggiornati dal repository.

L'architettura MVVM pone una forte enfasi sulla separazione delle preoccupazioni per ciascuno di questi livelli. Separare gli strati ci avvantaggia come:

  • Modularità: l'implementazione interna di ogni livello può essere cambiata o scambiata senza influire sugli altri.
  • Maggiore testabilità: ogni livello può essere testato unitamente a dati falsi, cosa non possibile se il codice di ViewModel è scritto nel codice dietro la vista .

La costruzione:

Creare un nuovo progetto di applicazione WPF Creare un nuovo progetto di applicazione WPF

Crea tre nuove cartelle nella soluzione: modello , ViewModel e View ed elimina il MainWindow.xaml originale, solo per ottenere un nuovo inizio.

Crea 3 nuove cartelle nella soluzione

Crea tre nuovi elementi, ciascuno corrispondente a un livello separato:

  • Fare clic con il pulsante destro del mouse sulla cartella Modello e aggiungere un elemento di classe denominato HelloWorldModel.cs .
  • Fare clic con il tasto destro sulla cartella ViewModel e aggiungere un elemento di classe chiamato HelloWorldViewModel.cs .
  • Fare clic con il tasto destro sulla cartella View e aggiungere un oggetto Window (WPF) chiamato HelloWorldView.xaml .

Aggiungi i tre elementi

Alter App.xaml per puntare alla nuova vista

<Application x:Class="MyMVVMProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyMVVMProject"
             StartupUri="/View/HelloWorldView.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>
 

ViewModel:

Inizia con la costruzione del ViewModel per primo. La classe deve implementare l'interfaccia INotifyPropertyChanged , dichiarare un evento PropertyChangedEventHandler e creare un metodo per generare l'evento (fonte: MSDN: Come implementare la notifica di modifica della proprietà ). Quindi, dichiarare un campo e una proprietà corrispondente, assicurandosi di chiamare il metodo OnPropertyChanged() nel set accessor della proprietà. Il costruttore nell'esempio seguente viene utilizzato per dimostrare che il Modello fornisce i dati a ViewModel .

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using MyMVVMProject.Model;

namespace MyMVVMProject.ViewModel
{
    // Implements INotifyPropertyChanged interface to support bindings
    public class HelloWorldViewModel : INotifyPropertyChanged
    {
        private string helloString;

        public event PropertyChangedEventHandler PropertyChanged;

        public string HelloString
        {
            get
            {
                return helloString;
            }
            set
            {
                helloString = value;
                OnPropertyChanged();
            }
        }

        /// <summary>
        /// Raises OnPropertychangedEvent when property changes
        /// </summary>
        /// <param name="name">String representing the property name</param>
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        public HelloWorldViewModel()
        {
            HelloWorldModel helloWorldModel = new HelloWorldModel();
            helloString = helloWorldModel.ImportantInfo;
        }
    }
}
 

Modello:

Quindi, crea il modello . Come indicato in precedenza, il Modello fornisce i dati per ViewModel estraendoli da un repository (oltre a reinserirli nel repository per il salvataggio). Questo è dimostrato di seguito con il metodo GetData() , che restituirà una semplice List<string> . La logica aziendale viene applicata anche in questo livello e può essere vista nel metodo ConcatenateData() . Questo metodo costruisce la frase "Hello, world!" List<string> che è stato precedentemente restituito dal nostro "repository".

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyMVVMProject.Model
{
    public class HelloWorldModel
    {
        private List<string> repositoryData;
        public string ImportantInfo
        {
            get
            {
                return ConcatenateData(repositoryData);
            }
        }

        public HelloWorldModel()
        {
            repositoryData = GetData();
        }

        /// <summary>
        /// Simulates data retrieval from a repository
        /// </summary>
        /// <returns>List of strings</returns>
        private List<string> GetData()
        {
            repositoryData = new List<string>()
            {
                "Hello",
                "world"
            };
            return repositoryData;
        }

        /// <summary>
        /// Concatenate the information from the list into a fully formed sentence.
        /// </summary>
        /// <returns>A string</returns>
        private string ConcatenateData(List<string> dataList)
        {
            string importantInfo = dataList.ElementAt(0) + ", " + dataList.ElementAt(1) + "!";
            return importantInfo;
        }
    }
}
 

Vista:

Infine, la vista può essere costruita. Non c'è nulla che deve essere aggiunto al codice dietro per questo esempio, anche se questo può variare a seconda delle esigenze dell'applicazione. Tuttavia, ci sono alcune linee aggiunte a XAML. La Window bisogno di un riferimento allo spazio dei nomi ViewModel . Questo è mappato allo spazio dei nomi XAML xmlns:vm="clr-namespace:MyMVVMProject.ViewModel" . Successivamente, la finestra ha bisogno di un DataContext . Questo è impostato su <vm:HelloWorldViewModel/> . Ora l'etichetta (o il controllo di tua scelta) può essere aggiunta alla finestra. Il punto chiave in questa fase è assicurarsi di impostare il binding sulla proprietà del ViewModel che si desidera visualizzare come contenuto dell'etichetta. In questo caso, è {Binding HelloString} .

È importante associare alla proprietà e non al campo, poiché nel secondo caso la vista non riceverà la notifica che il valore è cambiato, poiché il metodo OnPropertyChanged() solleverà il PropertyChangedEvent sulla proprietà e non sul campo.

<Window x:Class="MyMVVMProject.View.HelloWorldView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyMVVMProject.View"
        xmlns:vm="clr-namespace:MyMVVMProject.ViewModel"
        mc:Ignorable="d"
        Title="HelloWorldView" Height="300" Width="300">
    <Window.DataContext>
        <vm:HelloWorldViewModel/>
    </Window.DataContext>
    <Grid>
        <Label x:Name="label" FontSize="30" Content="{Binding HelloString}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>