Blog Dla Programistów C#/.NET

Dzisiaj na warsztat bierzemy MVVM (Model-View-ViewModel) – jeden z najpopularniejszych wzorców projektowych, używany głównie w aplikacjach desktopowych (WPF), mobilnych (Xamarin, .NET MAUI), a nawet w niektórych webowych frameworkach Blazor (w pewnym zakresie). Skupimy się tutaj na przykładzie WPF w C#, żebyś zrozumiał(a) sedno MVVM i mógł szybko zacząć tworzyć własne aplikacje.

Wzorzec MVVM w C#/.NET: Praktyczne Wprowadzenie dla Początkujących

Czym jest MVVM?


MVVM to wzorzec projektowy (ang. Model-View-ViewModel), który ma na celu:

    • Oddzielenie logiki biznesowej (Model) od warstwy prezentacji (View).
    • Ułatwienie testowania i rozwoju aplikacji.
    • Usprawnienie zarządzania stanem i danymi aplikacji w sposób bardziej strukturalny niż np. w prostym code-behind.

Kluczowe elementy MVVM:

    1. Model – reprezentuje dane i logikę biznesową (np. obiekty z bazy danych, operacje, walidacje).
    2. View – odpowiada za prezentację (np. okno WPF lub strona XAML w .NET MAUI).
    3. ViewModel – "most" między View a Modelem, zarządza logiką prezentacji i zapewnia mechanizmy wiązania danych (binding).

W WPF MVVM wspierany jest przez:

    • Data Binding – wiązania obiektów C# z elementami UI.
    • INotifyPropertyChanged – interfejs informujący widok o zmianach w modelu.
    • Commands – polecenia zamiast zdarzeń (Click itp.) w "code-behind".


Przykładowa aplikacja WPF z MVVM


Pokażę Ci prosty przykład aplikacji WPF, w której możemy edytować dane o osobach (imiona, nazwiska) i zobaczyć, jak działa natychmiastowe odświeżanie w widoku.


1. Model


W katalogu Models utwórzmy klasę Person.cs:

namespace MyMvvmApp.Models
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

Tu nie dzieje się wiele – mamy po prostu dane, czyli nasz "Model". Gdybyśmy korzystali z bazy danych czy API, to w tym miejscu moglibyśmy zaimplementować logikę dostępu do danych.


2. ViewModel


W katalogu ViewModels utwórzmy klasę MainViewModel.cs, która:

    • Będzie przechowywać obiekt Person.
    • Zaimplementuje interfejs INotifyPropertyChanged po to, by View (XAML) wiedział o wszelkich zmianach w danych.
    • Zawiera proste polecenie (komendę) do np. "zaktualizowania" danych lub wyświetlenia komunikatu. 

using MyMvvmApp.Models;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace MyMvvmApp.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
private Person _currentPerson;
public Person CurrentPerson
{
get => _currentPerson;
set
{
_currentPerson = value;
OnPropertyChanged();
}
}

// Prostą komendę możemy zaimplementować np. w taki sposób: public ICommand UpdateCommand { get; set; }

public MainViewModel()
{
// Inicjalizujemy dane CurrentPerson = new Person
{
FirstName = "Jan",
LastName = "Kowalski"
};

// Przypisanie komendy do delegata UpdateCommand = new RelayCommand(
execute: _ => UpdatePerson(),
canExecute: _ => true
);
}

private void UpdatePerson()
{
// Przykładowa logika, np. w realnej aplikacji zapiszemy do bazy itp.
// Tutaj wyświetlimy tylko w Debug output: System.Diagnostics.Debug.WriteLine(
$"Zaktualizowano dane: {CurrentPerson.FirstName} {CurrentPerson.LastName}"
);
}

public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

RelayCommand
W powyższym kodzie używamy klasy RelayCommand, którą musimy jeszcze zdefiniować. Dzięki niej szybko tworzymy komendy w MVVM. Dodaj do projektu plik RelayCommand.cs:

using System;
using System.Windows.Input;

namespace MyMvvmApp.ViewModels
{
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;

public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}

public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}

public void Execute(object parameter)
{
_execute(parameter);
}

public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
}

Ta prosta implementacja ICommand pozwala nam tworzyć w ViewModel komendy, które można zbindować do przycisków w View bez pisania zdarzeń (Click) w code-behind.


3. View (XAML)


Zostajemy w domyślnym pliku MainWindow.xaml (lub tworzymy nowy plik XAML, który będzie naszym głównym widokiem). Najważniejsza jest deklaracja kontekstu danych (DataContext) – zrobimy to w konstruktorze code-behind (pokazując, że staramy się minimalizować logikę w pliku .xaml.cs).

MainWindow.xaml

<Window x:Class="MyMvvmApp.MainWindow"
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:local="clr-namespace:MyMvvmApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MVVM Demo" Height="200" Width="300"
mc:Ignorable="d">

<Grid>
<StackPanel Margin="10">
<TextBlock Text="Imię:" FontWeight="Bold"/>
<TextBox Text="{Binding CurrentPerson.FirstName, UpdateSourceTrigger=PropertyChanged}" />

<TextBlock Text="Nazwisko:" FontWeight="Bold" Margin="0,10,0,0"/>
<TextBox Text="{Binding CurrentPerson.LastName, UpdateSourceTrigger=PropertyChanged}" />

<Button Content="Zaktualizuj"
Margin="0,10,0,0"
Command="{Binding UpdateCommand}" />
</StackPanel>
</Grid>
</Window>

W powyższym kodzie:

    • TextBox ma przypisane Text="{Binding CurrentPerson.FirstName}". To znaczy, że gdy zmieni się właściwość CurrentPerson.FirstName we ViewModelu, to automatycznie zmieni się tekst w kontrolce (i odwrotnie, jeśli użytkownik coś wpisze, wartość w ViewModelu też się zmieni).
    • Button jest powiązany przez Command="{Binding UpdateCommand}". Oznacza to, że kliknięcie w przycisk wywoła metodę UpdatePerson() we ViewModelu.

MainWindow.xaml.cs (code-behind)

using System.Windows;
using MyMvvmApp.ViewModels;

namespace MyMvvmApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

// Ustawiamy DataContext this.DataContext = new MainViewModel();
}
}
}

W code-behind ustawiamy DataContext na nową instancję MainViewModel. Dzięki temu całe wiązanie danych w XAML będzie odnosić się do obiektów i właściwości w MainViewModel.


Jak to wszystko działa?


    1. ViewModel – MainViewModel – posiada obiekt CurrentPerson i reaguje na zmiany właściwości dzięki INotifyPropertyChanged.
    2. View – MainWindow z XAML – wiąże pola tekstowe do CurrentPerson.FirstName i CurrentPerson.LastName. Gdy użytkownik wprowadza dane, zmienia się obiekt w ViewModelu.
    3. Command – RelayCommand – klasa implementująca ICommand, pozwala na powiązanie przycisku z metodą UpdatePerson() w ViewModelu, bez pisania zdarzeń w code-behind.
    4. Minimalna logika w code-behind – jedyne, co robimy w pliku .xaml.cs, to ustawiamy DataContext (lub ewentualnie inne rzeczy niezbędne do startu aplikacji).

Rezultat? Czystszy kod, większa testowalność (możesz przetestować sam ViewModel bez interfejsu graficznego), a także klarowny podział obowiązków w aplikacji.


Kilka słów o testach jednostkowych


Dzięki MVVM możesz bez problemu napisać testy jednostkowe, np. do sprawdzenia, czy UpdatePerson() zmienia jakieś inne właściwości ViewModelu, lub czy CanExecute danej komendy zwraca oczekiwane wartości. Nie musisz do tego w ogóle uruchamiać interfejsu graficznego. To właśnie jest jedna z największych zalet MVVM – większa testowalność aplikacji.


Podsumowanie


Wzorzec MVVM to świetny sposób na oddzielenie warstwy prezentacji od logiki biznesowej. Dzięki temu:

    • Łatwiej utrzymać i rozwijać aplikację.
    • Kod staje się bardziej testowalny.
    • Nasza aplikacja jest czytelna dla większego zespołu.

Jeśli chcesz poznać więcej szczegółów na temat tworzenia aplikacji w C#, .NET, WPF czy Blazor, a także opanować inne kluczowe zagadnienia, zapraszam Cię do mojego szkolenia online "Zostań Programistą .NET". Znajdziesz tam nie tylko omówienie fundamentów, ale również praktyczne projekty, dzięki którym nauczysz się efektywnie wykorzystywać możliwości platformy .NET.
Daj znać w komentarzu, czy udało Ci się uruchomić swoją pierwszą aplikację w MVVM!

To wszystkie na dzisiaj. Jeżeli taki artykuł Ci się spodobał, to koniecznie dołącz do mojej społeczności – darmowe zapisy, gdzie będziesz również miał dostęp do dodatkowych materiałów i przede wszystkim bonusów. Do zobaczenia w kolejnym artykule.

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!

Zostańmy w kontakcie!

Dołącz do mojej listy mailowej, aby otrzymywać ciekawe informacje ze świata programowania. Dodatkowo będziesz informowany o nowych artykułach na blogu, a także otrzymasz wyjątkowe rabaty na moje kursy i szkolenia.

    Nienawidzę spamu, dlatego będziesz otrzymywał tylko wartościowe maile. Możesz zrezygnować z subskrypcji w dowolnym momencie ✅

    © Copyright 2025 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin
    Serwis wykorzystuje pliki cookies. Korzystając ze strony wyrażasz zgodę na wykorzystywanie plików cookies. dowiedz się więcej.