27 September 2023

MVVM: Application
Development with MVVM Architecture

Published on 27 September 2023

MVVM: Application Development with MVVM Architecture

To create an application that is easy to test and maintain, you need to be familiar with design patterns, and one of the best options is MVVM. 

MVVM is a development pattern that allows you to divide an application into three functional parts:

· Model: The main logic of the program (working with data, calculations, queries, and more).

· View: The application's user interface.

· ViewModel: Serves as a bridge between View and Model.This separation allows you to speed up the development and maintainability of the program — you can change one component without affecting the code of another.

This separation accelerates development and makes it easier to maintain the program since you can modify one component without affecting the code of another. However, MVVM may be challenging to master because it differs significantly from more common patterns like MVC and event-driven application development.

How MVVM works

Let's illustrate this pattern with a real-world example: a celebrity, a PR manager, and the press.

  • Celebrity (Model): Focuses on their work without handling promotion directly. They      inform their manager when there's something press-worthy.
  • PR manager (ViewModel): Receives information from the celebrity and conveys it to the press. They might also handle interview requests and collaboration offers from publications.
  • Press (View): Writes articles based on information received from the celebrity's PR manager.

All these components collaborate, but their internal workings remain independent. For instance, the press can change its editorial team, newspaper layout, authors, or ownership without impacting the PR manager's work. This pattern enables developers to modify specific parts of the application without affecting others. A developer can also concentrate on one component without needing to understand the inner workings of others, although comprehending all aspects of application development is essential for a holistic understanding.

Practice: Writing an MVVM Application

MVVM can be implemented in iOS and Android development, but it's most commonly used in WPF (Windows Presentation Foundation) development. This isn't surprising as Microsoft introduced MVVM for developing graphical interface applications on Windows.

To understand this pattern, let's create a task list application using WPF. Start by creating a WPF project and adding the following class as your model:

public class Customer : INotifyPropertyChanged //Connecting an interface that allows you to notify about a state change

{

//Task Data

private string name;

private string task;

private int price;

private DateTime deadline;

private bool isSolved;

public Customer(string name, string task, int price, DateTime deadline) //Simple Constructor

{

this.name = name;

this.task = task;

this.price = price;

this.deadline = deadline;

this.isSolved = false;

}

//Getters and Setters

public string Name

{

get

{

return this.name;

}

}

public string Task

{

get

{

return this.task;

}

}

public int Price

{

get

{

return this.price;

}

}

public string DeadlineString

{

get

{

return $"{this.deadline.Day}.{this.deadline.Month}.{this.deadline.Year}";

}

}

public bool IsSolved

{

get

{

return this.isSolved;

}

set

{

this.isSolved = value; 

OnPropertyChanged("IsSolved"); //If the property changes, we call the method that notifies about the model change

OnPropertyChanged("Color"); //If several values are changed, you can call an additional method

}

}

public string Color

{

get

{ //If the problem is solved, the blue color will be returned, otherwise it will depend on whether the deadline has passed

return this.isSolved ? "Blue" : DateTime.Now.CompareTo(this.deadline) == -1 ? "Black" : "Red";

}

}

public event PropertyChangedEventHandler PropertyChanged; //Event that will be triggered when the model changes

public void OnPropertyChanged([CallerMemberName]string prop = "") //A method that tells the ViewModel to pass new data to the view

{

if (PropertyChanged != null)

PropertyChanged(this, newPropertyChangedEventArgs(prop));

}

}

Now create a view model:

public class AppViewModel : INotifyPropertyChanged

{

private Customer selectedCustomer;

private ObservableCollection<Customer> customers;

public AppViewModel()

{

customers = newObservableCollection<Customer>() //Adding data for testing

{

new Customer("Josh", "Fix printer", 500, new DateTime(2019, 5, 11)),

new Customer("Josh", "Install fax", 350, new DateTime(2019, 6, 15)),

new Customer("Tyler", "Update soft", 100, new DateTime(2019, 6, 17)),

new Customer("Nico", "Install antivirus", 400, new DateTime(2019, 6, 19)),

new Customer("Tyler", "Fix printer", 500, new DateTime(2019, 6, 21)),

new Customer("Nico", "Update soft", 200, new DateTime(2019, 6, 27))

};

}

public Customer SelectedCustomer

{

get

{

return this.selectedCustomer;

}

set

{

this.selectedCustomer = value;

OnPropertyChanged("SelectedCustomer");

}

}

public ObservableCollection<Customer> Customers

{

get

{

return this.customers;

}

}

public event PropertyChangedEventHandler PropertyChanged;

public void OnPropertyChanged([CallerMemberName]string prop = "")

{

if (PropertyChanged != null)

PropertyChanged(this, newPropertyChangedEventArgs(prop));

}

}

An instance of this class will be utilized to facilitate data and command exchange between the model and the view. Next, you should create a View interface for the program:

<Window.Resources>

<Style x:Key="Text">

<Setter Property="TextBlock.Margin" Value="5"/>

<Setter Property="TextBlock.FontSize" Value="14"/>

</Style>

<Style BasedOn="{StaticResource Text}" TargetType="TextBlock"></Style>

<Style x:Key="BoldText" BasedOn="{StaticResource Text}">

<Setter Property="TextBlock.FontWeight" Value="DemiBold"/>

</Style>

</Window.Resources>

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="1*"/>

<ColumnDefinition Width="1*"/>

</Grid.ColumnDefinitions>

<Border Padding="5">

<ListBox ItemsSource="{Binding Customers}" SelectedItem="{Binding SelectedCustomer}" ScrollViewer.VerticalScrollBarVisibility="Auto">

<ListBox.ItemTemplate>

<DataTemplate>

<StackPanel>

<TextBlock Text="{Binding Name}" FontSize="16" FontWeight="DemiBold" Background="{x:Null}"/>

<TextBlock Text="{Binding Task}"/>

<TextBlock Text="{Binding DeadlineString}" TextAlignment="Right" Foreground="{Binding Color}"/>

</StackPanel>

</DataTemplate>

</ListBox.ItemTemplate>

</ListBox>

</Border>

<Border Grid.Column="1" Margin="5">

<StackPanel DataContext="{Binding SelectedCustomer}">

<TextBlock Text="Customer" TextAlignment="Center" FontSize="16" Style="{StaticResource BoldText}"/>

<DockPanel>

<TextBlock Text="Name: " Style="{StaticResource BoldText}"/>

<TextBlock Text="{Binding Name}"/>

</DockPanel>

<DockPanel>

<TextBlock Text="Task: " Style="{StaticResource BoldText}"/>

<TextBlock Text="{Binding Task}"/>

</DockPanel>

<DockPanel>

<TextBlock Text="Deadline: " Style="{StaticResource BoldText}"/>

<TextBlock Text="{Binding DeadlineString}"/>

</DockPanel>

<DockPanel>

<TextBlock Text="Solved: " Style="{StaticResource BoldText}"/>

<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsSolved}"/>

</DockPanel>

</StackPanel>

</Border>

</Grid>

In this code, you can replace a crucial part of any MVVM application - data binding. Instead of manually specifying values in the interface, they are automatically added thanks to a similar argument:

{Binding Task}

This instructs the program to retrieve (bind) data from the Task property. Simultaneously, the list itself has the following specified in the ItemsSource attribute:

{Binding Customers}

This means it retrieves the Customers collection and displays its elements according to the DataTemplate template. If any element changes, it will immediately be displayed in the application thanks to calling the OnPropertyChanged() method.

However, to use data binding, you first need to instruct the application where to obtain the data. To do this, add the following line in the MainWindow.xaml.cs file:

DataContext = new AppViewModel();

Furthermore, you don't need to add anything else — the application will function without event handlers.

For example, if the user clicks on the CheckBox, the value is immediately sent to the model. In this case, two-way data binding is used: it not only transmits the value from the model to the view but also notifies the model that something has changed.

Conclusion

MVVM is indeed one of the best patterns, as it enables a focus on creating the interface or application logic without the need for manually registering event handlers or controller operations, as in MVC.

However, the main drawback of MVVM is its learning curve. In addition to data binding, you also need to work with commands, and some actions may require creating additional classes or methods in the MainWindow.xaml.cs file. Despite this, mastering MVVM can greatly improve the maintainability and testability of your applications, making it a valuable pattern to learn.

Recommended Tutorials

Stay updated with our latest articles, industry insights, and expert tips to keep your business informed and inspired.