How-To: Navigation in the Model or ViewModel
Now let's take a look at how we need to structure the connection between the View and the ViewModel to work with Uno Extensions Navigation.
First, let's ask ourselves the question: Navigation only in Xaml - Is that even possible?
Yes and No.
So, let's take a closer look. What does this mean?
Yes:
In fact, you basically don't need either codebehind or code in the ViewModel / Model for navigation if you use the
Attached Propertiesin the Xaml of your page.If you're interested in how this works, you can find it directly here:
How-To: Defining the UI with NavigationView for ExtensionsNavigation
In this case, it would typically only be the properties to display, like the
stringpropertyTitle, that you bind from yourPage, i.e., yourViewto theViewModelorModel, and you're done!Tip
By the way, with the
Attached Propertiesuen:Navigation.Requestanduen:Navigation.Datayou can also pass data to navigation, as explained well in the Uno documentation usingWidgetelements as examples. However, for this you'll needDataViewMapdefinitions in the route registration.No:
- You still need to register the routes you want to navigate in the
RegisterRoutesmethod in theApp.xaml.csclass, so theINavigatorknows what belongs together and from where you want to allow navigation to which routes with which "qualifiers". - If you want to trigger navigation in your Model or ViewModel, then of course you need the
INavigatorthere to start the navigation.
- You still need to register the routes you want to navigate in the
Creating the Prerequisites
Okay, so let's assume we have the second case mentioned above and want to do the following:
Our user should be able to trigger a function in our
ViewModelorModelby clicking aButtonThis function should navigate them to the
SecondPagethat we included in the Uno App template, but it could also be any other page you created and registered yourself.Let's assume this is our
App.xaml.cswith theRegisterRoutesmethod:{ views.Register( new ViewMap(ViewModel: typeof(ShellModel)), new ViewMap<MainPage, MainModel>(), new DataViewMap<SecondPage, SecondViewModel, Entity>() ); routes.Register( new RouteMap("", View: views.FindByViewModel<ShellModel>(), Nested: [ new RouteMap("Main", View: views.FindByViewModel<MainModel>(), IsDefault:true), new RouteMap("Second", View: views.FindByViewModel<SecondModel>()) ] ) ); }
But how should our ViewModel or Model look so we can implement this?
For this we need the following steps:
Prerequisites
Binding View UI Controls to Properties in the ViewModel or Model
Now we have previously set the Title of the NavigationView manually, but what about other properties that we want to bind in the View? And you may have also seen the Name defined in the Dashboard(View)Model in the template app.
If you're not starting from the template, add this property to bind it in the View.
public string? Name { get; set; }
public partial class DashboardViewModel : ObservableObject
{
private readonly INavigator _navigator;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(NavigateSecondAsyncCommand))]
private string? name;
public DashboardViewModel(INavigator navigator)
{
_navigator = navigator;
NavigateSecondAsyncCommand = new AsyncRelayCommand(NavigateSecondAsync);
}
public IAsyncRelayCommand NavigateSecondAsyncCommand { get; }
[RelayCommand(CanExecute = nameof(CanExecuteNavigateSecondAsync))]
private async Task NavigateSecondAsync()
{
await _navigator.NavigateViewModelAsync<SecondViewModel>(this, data: new Entity(Name!));
}
private bool CanExecuteNavigateSecondAsync()
{
return !string.IsNullOrWhiteSpace(Name);
}
}
With this code, you can bind the Name property in the View and use the NavigateSecondAsyncCommand to navigate to the SecondViewModel.
You can use a button or another control in the View to trigger navigation, but by binding the IsEnabled property of the control to the CanExecute status of the command, you can only execute navigation when the name is not empty.