mvvm Samouczek
Rozpoczęcie pracy z mvvm
Szukaj…
Uwagi
Ta sekcja zawiera przegląd tego, czym jest mvvm i dlaczego deweloper może chcieć go użyć.
Powinien także wymieniać wszelkie duże tematy w mvvm i link do powiązanych tematów. Ponieważ Dokumentacja dla mvvm jest nowa, może być konieczne utworzenie początkowych wersji tych pokrewnych tematów.
Podsumowanie C # MVVM i kompletny przykład
Streszczenie:
MVVM jest wzorem architektonicznym reprezentowanym przez trzy różne komponenty: Model , Widok i Model ViewModel . Aby zrozumieć te trzy warstwy, konieczne jest krótkie zdefiniowanie każdej z nich, a następnie wyjaśnienie, w jaki sposób działają one razem.
Model jest warstwą, która napędza logikę biznesową. Pobiera i przechowuje informacje z dowolnego źródła danych do wykorzystania przez ViewModel .
ViewModel to warstwa, która działa jak pomost między widokiem a modelem . Może, ale nie musi, przekształcić nieprzetworzonych danych z Modelu w formę do prezentacji dla Widoku . Przykładową transformacją byłoby: flaga logiczna z modelu na ciąg „Prawda” lub „Fałsz” dla widoku.
Widok to warstwa reprezentująca interfejs oprogramowania (tj. GUI). Jego rolą jest wyświetlanie użytkownikowi informacji z ViewModel i przekazywanie zmian informacji z powrotem do ViewModel .
Te trzy składniki działają razem, odwołując się do siebie w następujący sposób:
- Widok odwołuje się do ViewModel .
- ViewModel odwołuje się do modelu .
Należy zauważyć, że View i ViewModel są zdolne do dwukierunkowej komunikacji zwanej wiązaniem danych .
Głównym składnikiem dwukierunkowej komunikacji (wiązania danych) jest interfejs INotifyPropertyChanged .
Korzystając z tego mechanizmu, widok może modyfikować dane w ViewModel poprzez wprowadzanie danych przez użytkownika, a ViewModel może aktualizować widok o dane, które mogły zostać zaktualizowane za pomocą procesów w modelu lub o zaktualizowane dane z repozytorium.
Architektura MVVM kładzie duży nacisk na rozdzielenie obaw dla każdej z tych warstw. Rozdzielenie warstw przynosi nam korzyści, ponieważ:
- Modułowość: Wewnętrzną implementację każdej warstwy można zmienić lub zamienić bez wpływu na inne.
- Zwiększona testowalność: Każda warstwa może być testowana jednostkowo z fałszywymi danymi, co nie jest możliwe, jeśli kod ViewModel jest zapisany w Code-Behind of View .
Kompilacja:
Utwórz nowy projekt aplikacji WPF
Utwórz trzy nowe foldery w swoim rozwiązaniu: Model , ViewModel i Widok , a następnie usuń oryginalny MainWindow.xaml
, aby rozpocząć od nowa.
Utwórz trzy nowe elementy, każdy odpowiadający osobnej warstwie:
- Kliknij prawym przyciskiem myszy folder Model i dodaj element klasy o nazwie
HelloWorldModel.cs
. - Kliknij prawym przyciskiem myszy folder ViewModel i dodaj element klasy o nazwie
HelloWorldViewModel.cs
. - Kliknij prawym przyciskiem myszy folder View i dodaj element Window (WPF) o nazwie
HelloWorldView.xaml
.
Zmień App.xaml
aby wskazać nowy Widok
<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:
Zacznij od zbudowania ViewModel w pierwszej kolejności. Klasa musi zaimplementować interfejs INotifyPropertyChanged
, zadeklarować zdarzenie PropertyChangedEventHandler
i utworzyć metodę podniesienia zdarzenia (źródło: MSDN: jak zaimplementować powiadomienie o zmianie właściwości ). Następnie zadeklaruj pole i odpowiednią właściwość, upewniając się, że wywołujesz metodę OnPropertyChanged()
w akcesorium set
właściwości. Konstruktor w poniższym przykładzie jest używany do wykazania, że Model dostarcza dane do 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;
}
}
}
Model:
Następnie zbuduj model . Jak wspomniano wcześniej, Model udostępnia dane dla ViewModel poprzez pobranie go z repozytorium (jak również wypchnięcie go z powrotem do repozytorium w celu zapisania). Jest to pokazane poniżej za pomocą metody GetData()
, która zwróci prostą List<string>
. Logika biznesowa jest również stosowana w tej warstwie i można ją zobaczyć w metodzie ConcatenateData()
. Ta metoda buduje zdanie „Witaj, świecie!” z List<string>
która została wcześniej zwrócona z naszego „repozytorium”.
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;
}
}
}
Widok:
Wreszcie View można budować. W tym przykładzie nic nie trzeba dodawać do kodu, chociaż może się to różnić w zależności od potrzeb aplikacji. Istnieje jednak kilka wierszy dodanych do XAML. Window
potrzebuje odniesienia do przestrzeni nazw ViewModel
. Jest to mapowane do przestrzeni nazw XAML xmlns:vm="clr-namespace:MyMVVMProject.ViewModel"
. Następnie okno potrzebuje DataContext
. Ustawiono na <vm:HelloWorldViewModel/>
. Teraz etykietę (lub wybraną przez ciebie kontrolkę) można dodać do okna. Kluczowym punktem na tym etapie jest upewnienie się, że ustawiono Powiązanie na właściwość ViewModel, która ma być wyświetlana jako treść etykiety. W tym przypadku jest to {Binding HelloString}
.
Ważne jest powiązanie z właściwością, a nie z polem, ponieważ w tym drugim przypadku widok nie otrzyma powiadomienia o zmianie wartości, ponieważ metoda OnPropertyChanged()
podniesie PropertyChangedEvent
dla właściwości, a nie dla właściwości pole.
<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>