I'm trying to follow the Model–View–ViewModel
pattern in a Xamarin application and am wondering how the View should be able to change when a given ViewModel is finished. Below I have listed the ideas I have come up with doing what I need.
Creating the new View directly in the ViewModel.
Currently, each ViewModel explicitly sets the Application's MainPage to a different View when the ViewModel is done; I believe this violates the MVVM pattern because while each ViewModel doesn't know about its own View it does know about the View that follows it. Here is an example inside a ViewModel:
private async Task ExecuteSubmitCommand()
{
// Do stuff here.
// Go to a different page.
Application.Current.MainPage = new Views.NewUploadWizardPage(this.imageBatch, appInfo);
}
While this is easy to do I feel like it is not a best practice and it makes testing the ViewModel very difficult.
Sending a message from the ViewModel to signal that it is finished.
With this approach, there could be a "view controller" object that persists the lifetime of the program and handles the creation of new Views. This controller object could subscribe to messages which are sent from the ViewModels to know when to switch Views. Example:
Controller:
private void Method1()
{
Application.Current.MainPage = new ImageBatchEntryView();
MessagingCenter.Subscribe<ImageBatchEntryViewModel>(this, "Finished", async (vm, tuple) => await Method2(vm, tuple));
}
private async Task Method2(ImageBatchEntryViewModel vm, Tuple<ImageBatch, AppInfo> tuple)
{
MessagingCenter.Unsubscribe<ImageBatchEntryViewModel>(this, "Finished");
Application.Current.MainPage = new Views.NewUploadWizardPage(tuple.Item1, tuple.Item2);
MessagingCenter.Subscribe<NewUploadWizardViewModel>(this, "Finished", async (vm, something) => await Method3(vm, something));
}
ViewModel:
private async Task ExecuteSubmitCommand()
{
// Do stuff here.
// Send message.
MessagingCenter.Send(this, "Finished", new Tuple<ImageBatch, AppInfo>(this.imageBatch, appInfo));
}
Raising an event in the ViewModel to signal that is is finished.
This is similar to the message approach but uses events instead. The "view controller" object could just subscribe to an event in a ViewModel and change the View when that event is raised.
Other Ideas?
Is there an approach that's considered best practice for having ViewModels initiating View changes?