Calling methods in your View from your ViewModel using Action-Invokes

Executing ViewModel methods from Xamarin Forms Pages is easy, but how can Page methods be called inside ViewModels?

The First Prototype

--

In Xamarin Forms, if you bind ViewModel Commands to Page Buttons, all of the logic from the button click action takes place in the ViewModel. The problem is that the ViewModel doesn’t have access to the Xamarin Forms controls, and so it’s difficult to access functions of Views from your ViewModel. Delegates are not commonly used, so I hope this article adds another tool in your arsenal that you can use to solve your coding challenges. Note that Action delegates can be used for all UI frameworks that use C#.

Example use case: Focus on an Entry

Let’s look at a scenario where we have a Password Entry and a Login Button on a Login Page. Our requirement is that if the password is incorrect, we want the password entry to automatically have the keyboard focus. Generally, validity of password is determined through the ViewModel using your Services layer, and that class is responsible for navigation if the password is right. But if the password is incorrect, and you want the UI to react to that error, it would be difficult to do it using traditional means.

Photo by ThisisEngineering RAEng on Unsplash

Say hello to Action Invoke

Now, we can create an event in the ViewModel, and a corresponding event handler in the Page. So, every time that event is invoked anywhere in the ViewModel, that event handler method automatically gets called in the Page.

ViewModel Changes

As you can see in this sample, all you need where you services determine that the login has failed and you want the Password Entry to get the focus, is two lines of code in your ViewModel:
declaration of the event public Action<bool> OnLoginFailed { get; set; } and then simply executing thisOnLoginFailed?.Invoke(true);.

Page Changes

In the Page, you simply assign the event handler to perform the action:

ViewModel.OnLoginFailed = ((obj) =>
{
PasswordEntry.Focus();
});

--

--