I’m a creature of habit. I like my projects in MVVM and I tend to set them up a very particular way. If you’ve worked with the MVVM pattern before, you probably have your own methodologies, but if you’re new to the pattern (here’s a quick primer from Microsoft), here are some general rules I try to follow that can get you started. This proposal assumes you are using MVVMLight (which is perhaps the most ubiquitous) , but the general principles apply to similar frameworks, such as Prism and Xamvvm.
Naming Conventions
Views and their related ViewModels should be clearly identifiable for name.
- For Views: {SomeDescriptor}Page
- For ViewModels: {NameOfCorrespondingView}ViewModel
For example:
- Views Folder
- OrderPage.xaml
- OrderPage.xaml.cs
- ViewModels Folder
- OrderPageViewModel.cs
Making a New Page Using End-To-End MVVM
Here’s a high-level overview on getting a new page set up and ready for MVVM. This section assumes you have already configured your Dependency Injection, have implemented INavigationService, and have already established your navigation page.
- Create a new View in the Views folder
- Create a new ViewModel in the ViewModels folder
- In the constructor of the ViewModel, inherit from ViewModelBase
public class HomeDashboardViewModel : ViewModelBase
{
/*
* Define Fields
*/
// TODO:
/*
* Define Properties
*/
// TODO:
/*
* Define Commands
*/
// TODO:
public HomeDashboardViewModel(INavigationService navigationService)
{
this.Title = "Home";
}
/*
* Define Methods
*/
// TODO:
}
Notice that we need to provide the INavigationService (discussed later) to the constructor, which will be resolved by our DI container.
- Register the ViewModel in IoCConfig.cs
/// <summary>
/// Registers the view models.
/// </summary>
public void RegisterViewModels()
{
SimpleIoc.Default.Register<OrderPageViewModel>();
SimpleIoc.Default.Register<HomeDashboardViewModel>();
// TODO INIT: Register new ViewModels here
}
- Register the ViewModel in ViewModelLocator.cs
/*
* Define ViewModels
*/
public OrderPageViewModel OrderView => ServiceLocator.Current.GetInstance<OrderPageViewModel>();
public HomeDashboardViewModel HomeDashboardView => ServiceLocator.Current.GetInstance<HomeDashboardViewModel>();
// TODO INIT: Add new ViewModels Here
- Register the view Nacvigation in IoCConfig.cs
/// <summary>
/// Handles navigation wire up
/// </summary>
public void RegisterNavigation()
{
var navigationService = new NavigationService();
navigationService.Configure(nameof(Views.HomeDashboardPage), typeof(Views.HomeDashboard));
navigationService.Configure(nameof(Views.OrderPage), typeof(Views.BulletinBoardNewItem));
// TODO INIT: Register new View here
SimpleIoc.Default.Register<INavigationService>(() => navigationService);
}
- Define your ViewModel in the View
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyMvvmApp"
BindingContext="{Binding Source={StaticResource Locator}, Path=OrderView}"
Title="Order Page">
From here, you’re ready to start using the MVVM pattern with MVVMLight!
Navigating To and From Your Page
// Forward
this._navigationService.NavigateTo(nameof(Views.HomeDashboardPage));
// Forward with parameters
this._navigationService.NavigateTo(nameof(Views.OrderPage), parameters);
// Back
this._navigationService.GoBack();
Binding ViewModel Properties in the View
Static properties can be added to the View do display a single value that never changes after the ViewModel is initialized:
<Label Text="{Binding Message}" Style="{StaticResource labelSubheading}">
Or, we can create a new property as observable, so that the View is updated anytime the value in the ViewModel changes. This can be very useful in many cases, like when wanting to show a loading indicator:
/*
* Define Properties
*/
private bool _isLoading;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
Set(() => IsLoading, ref _isLoading, value);
}
}
The binding on the View looks the same, but will always reflect the current state of IsLoading
<ListView IsRefreshing="{Binding IsLoading}">
Binding Commands in the View
Commands in MVVM Light are created using a RelayCommand, which is an observable implementation of ICommand. RelayCommands can be constructed with an optional “Can Execute” property, which define when the command can or cannot run. Create a new command in your ViewModel like so:
/*
* Define Commands
*/
public RelayCommand<ClassifiedAdTransferObject> SelectItemCommand { get; set; }
public RelayCommand AddItemCommand { get; set; }
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public BulletinBoardViewModel(INavigationService nav, IClassifiedAdService ClassifiedAdService) : base(nav)
{
_ClassifiedAdService = ClassifiedAdService;
SelectItemCommand = new RelayCommand<ClassifiedAdTransferObject>((s) => SelectItem(s));
AddItemCommand = new RelayCommand( () => AddItem());
Initialize();
}
/*
* Define Methods
*/
private void AddItem()
{
var pageName = nameof(Views.BulletinBoardPage);
_navigationService.NavigateTo(pageName);
}
private void SelectItem(ClassifiedAdTransferObject item)
{
// TODO: handle a click action and use the item parameter
}
This can then be bound to any element in the view that expects a command and (optional) command Parameter:
<Button Command="{Binding AddItemCommand}" Text="Show me a new page to add items">
With that, you’re ready to start developing with MVVM!
