I'm currently working on refactoring our mobile app from Xamarin to MAUI. In the Xamarin app, we use Prism for navigation, but we want to stop using that. For navigation, we followed Max Borrmanns approach here for triggering the OnAppearing()
function once moving to a page: https://learn.microsoft.com/en-us/answers/questions/1186365/net-maui-viewmodel-alternative-to-onappearing
In Prism, they have a function called OnNavigatedTo()
, which functions similarly, but also takes INavigationParameters
as input. so in Prism, when a page is being navigated to, the following is called:
public async void OnNavigatedTo(INavigationParameters parameters)
OnNavigatedTo()
is called and we don't have to explicitly define any parameters, they are just kind of available when its called. As a replacement I was thinking of doing something like this:
public async void OnAppearing(Dictionary<String, Object> parameters)
The problem with this approach is that the parameters have to be manually defined, which means we aren't actually using any navigation parameters, since we keep making new ones. Is there a native MAUI way of doing this?
Shell's GoToAsync()
provides the possibility to pass an IDictionary<string, object>
as can be seen in the documentation.
Your ViewModel then needs to implement IQueryAttributable
. This would be the "native" MAUI way using Shell, but you still need to explicitly provide the parameters, I'm not aware of some implicit mechanism.
Page:
public class SomePage : ContentPage
{
private readonly SomeViewModel _vm;
public SomePage(SomeViewModel vm)
{
_vm = vm;
}
}
ViewModel:
public partial class SomeViewModel : ObservableObject, IQueryAttributable
{
[ObservableProperty]
private SomeModel _myModel;
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
MyModel = query["model"] as SomeModel;
}
}
Register route for SomePage:
Routing.RegisterRoute("SomePage", typeof(SomePage));
Navigation:
await Shell.Current.GoToAsync("SomePage", new Dictionary<string,object>
{
{ "model", new SomeModel() }
});
You could also create an abstract BaseViewModel so that your ViewModels only need to inherit from that and override ApplyAttributes()
:
public abstract class BaseViewModel : ObservableObject, IQueryAttributable
{
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
ApplyAttributes(query);
}
protected virtual void ApplyAttributes(IDictionary<string, object> query) { }
}
public partial class SomeViewModel : BaseViewModel
{
[ObservableProperty]
private SomeModel _myModel;
protected override void ApplyAttributes(IDictionary<string, object> query)
{
MyModel = query["model"] as SomeModel;
}
}