MVVM Architecture - lucyberryhub/WPF.Tutorial GitHub Wiki
Darling, letโs structure your app like a berry parfait.
In the world of WPF applications, the MVVM (Model-View-ViewModel) pattern is a perfect way to structure your app, creating a clean and maintainable architecture. Imagine your app as a berry parfait, with each layer serving a specific role:
- Model: Your data layer (like berries ๐).
- ViewModel: The middle layer that holds the logic and communicates between the Model and View.
- View: The UI layer (the delicious top layer ๐ฐ).
In this tutorial, weโll dive into how each of these parts works together, helping you organize and scale your app effortlessly. Ready to build a berry-ful app with the MVVM architecture? Letโs get started!
In MVVM, the Model represents the data or business logic. For our berry-themed app, let's create a simple Berry
class to represent a berry. This class will have properties like Name
and any other details you might want to store about berries.
public class Berry
{
// Name of the Berry
public string Name { get; set; }
}
Berry Vibe:
- ๐ The
Berry
class is simple and just contains a single property:Name
. - This model holds the raw data and doesnโt include any UI logic or presentation-specific code.
The ViewModel acts as the intermediary between the Model and View. It contains the logic of the application and provides the data that the view binds to. It is responsible for updating the View based on changes to the Model and also responding to user interactions from the View.
using System.ComponentModel;
public class BerryViewModel : INotifyPropertyChanged
{
// Property to hold the current berry
private Berry _currentBerry;
// The current berry, which can be bound to the view
public Berry CurrentBerry
{
get { return _currentBerry; }
set
{
if (_currentBerry != value)
{
_currentBerry = value;
OnPropertyChanged(nameof(CurrentBerry));
}
}
}
// Constructor to initialize the Berry
public BerryViewModel()
{
CurrentBerry = new Berry { Name = "Strawberry" };
}
// INotifyPropertyChanged implementation to notify the view when a property changes
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Berry Vibe:
- ๐
CurrentBerry
: This property holds the berry object. When this property changes, it triggers thePropertyChanged
event, which tells the View to update itself with the new value. - ๐
INotifyPropertyChanged
: TheViewModel
implements this interface to notify the View when a property has changed. This is crucial for data-binding in WPF, as it ensures the UI automatically updates when the data changes. - ๐
OnPropertyChanged
: This method is used to trigger the property change event, allowing the View to react to changes in the ViewModel.
The View is the UI layer, and itโs responsible for displaying the data. With MVVM, the View will bind to the ViewModel to display the current berry's name. The View should have minimal logic; it only deals with layout and data binding.
<Window x:Class="BerryFarmApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Berry Farm" Height="350" Width="525">
<Window.DataContext>
<!-- Set the ViewModel as the DataContext of the window -->
<local:BerryViewModel />
</Window.DataContext>
<Grid>
<!-- Bind the TextBlock to the CurrentBerry's Name property in the ViewModel -->
<TextBlock Text="{Binding CurrentBerry.Name}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24" />
</Grid>
</Window>
Berry Vibe:
- ๐
Window.DataContext
: We set the ViewModel as theDataContext
of the window. This means the window (and any controls within it) can access the ViewModel and bind to its properties. - ๐
TextBlock
: This control is bound to theCurrentBerry.Name
property in the ViewModel using the{Binding}
syntax.- The
TextBlock
will display the name of the berry (e.g., โStrawberryโ) as defined in theBerryViewModel
. - Any change in the
CurrentBerry.Name
will automatically update theTextBlock
thanks to data-binding.
- The
Now, let's add a little interactivity! Letโs say we want to change the berry name when a button is clicked. Weโll create a button in the View and implement the logic in the ViewModel to update the berry name.
Letโs add a command in the ViewModel that will allow us to update the CurrentBerry.Name
when the button is clicked.
using System.ComponentModel;
using System.Windows.Input;
public class BerryViewModel : INotifyPropertyChanged
{
private Berry _currentBerry;
public Berry CurrentBerry
{
get { return _currentBerry; }
set
{
if (_currentBerry != value)
{
_currentBerry = value;
OnPropertyChanged(nameof(CurrentBerry));
}
}
}
public ICommand ChangeBerryCommand { get; }
public BerryViewModel()
{
CurrentBerry = new Berry { Name = "Strawberry" };
ChangeBerryCommand = new RelayCommand(ChangeBerry);
}
private void ChangeBerry()
{
CurrentBerry.Name = "Blueberry";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Berry Vibe:
- ๐
ChangeBerryCommand
: This command allows us to trigger theChangeBerry
method when a button is clicked. - ๐
RelayCommand
: This is a simple implementation of theICommand
interface, which makes it easy to handle button clicks in MVVM (you can use any command implementation you prefer). - ๐
ChangeBerry
: This method changes theName
of the current berry from โStrawberryโ to โBlueberry.โ
Letโs now add the button to the View that will trigger the change of berry name when clicked.
<Window x:Class="BerryFarmApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Berry Farm" Height="350" Width="525">
<Window.DataContext>
<local:BerryViewModel />
</Window.DataContext>
<Grid>
<!-- Display the Berry Name -->
<TextBlock Text="{Binding CurrentBerry.Name}" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="24" Margin="0,50,0,0"/>
<!-- Button to Change Berry -->
<Button Content="Change Berry" Command="{Binding ChangeBerryCommand}" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,50" Width="200"/>
</Grid>
</Window>
Berry Vibe:
- ๐
Button
: The button is bound to theChangeBerryCommand
in the ViewModel using theCommand
property.- When clicked, the
ChangeBerryCommand
will be executed, changing the berry's name from "Strawberry" to "Blueberry."
- When clicked, the
-
Model: The
Berry
class holds the data (like the berryโs name). -
ViewModel: The
BerryViewModel
class provides the logic and binds the data to the View. -
View: The
MainWindow.xaml
UI binds to theBerryViewModel
and displays the berryโs name. The View can also trigger updates to the data (like changing the berry name).
Benefits of MVVM:
- Separation of Concerns: MVVM separates the logic (ViewModel) from the UI (View), making your application easier to maintain and extend.
- Testability: The ViewModel contains the logic, which can be unit tested without worrying about UI components.
- Data Binding: MVVM relies heavily on data binding, making it easy to synchronize the UI with data and respond to changes without having to write extensive event-handling code.
With MVVM, your berry farm app is clean, maintainable, and easily extendable as it grows, just like the berries in your farm! ๐ Enjoy the structured approach that keeps your application as fresh as a berry parfait.