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!