Skip to content

Provides platform independent navigation at the MVVM level and a Source Generator that automatically binds view and view models and registers this in your DI container

License

Notifications You must be signed in to change notification settings

HavenDV/Mvvm.Navigation

Repository files navigation

CI/CD License: MIT Discord NuGet NuGet NuGet NuGet NuGet NuGet NuGet NuGet

Provides platform independent navigation at the MVVM level and a Source Generator that automatically binds view and view models and registers this in your DI container.

🔥Features🔥

  • Uses DI to resolve your view from view model.
  • Generates constructors for your views(optional).
  • Generates an extension method for you with all your Views and ViewModels to register them in DI.
  • Does not contain custom controls, everything happens based on the attached dependency property and does not limit the user.
  • Allows forward/backward navigation like in Chrome.
  • Allows you to receive activation/deactivation events - just implement IActivatableViewModel for your ViewModel.
  • Allows you to generate a typed ViewModel property via an attribute, bound to your BindingContext and initialized from DI.
  • Supports automatic mapping between View and ViewModel based on a global attribute.
  • Allows case-by-case, attribute-based control for Views.

Usage

  1. Add .AddMvvmNavigation() call to your Host builder or IServiceCollection:
public sealed partial class App
{
    public App()
    {
        AppHost = Host
            .CreateDefaultBuilder()
            .AddMvvmNavigation()
            .Build();
    }
}
  1. Add ViewFor attribute to your views:
using Mvvm.Navigation;

[ViewFor<MainViewModel>]
public partial class MainPage : UserControl;

or assembly level attribute(nameof behavior is ignored and the full namespace is taken):

[assembly:MapViews(
    viewsNamespace: nameof(MyNamespace.Views),
    viewModelsNamespace: nameof(MyNamespace.ViewModels))]

or in .csproj:

<ItemGroup Label="Navigation">
    <AssemblyAttribute Include="Mvvm.Navigation.MapViews">
        <_Parameter1>nameof(MyNamespace.Views)</_Parameter1>
        <_Parameter1_IsLiteral>true</_Parameter1_IsLiteral>
        <_Parameter2>nameof(MyNamespace.ViewModels)</_Parameter2>
        <_Parameter2_IsLiteral>true</_Parameter2_IsLiteral>
        <ViewLifetime>Mvvm.Navigation.ServiceLifetime.Transient</ViewLifetime>
        <ViewLifetime_IsLiteral>true</ViewLifetime_IsLiteral>
        <ViewModelLifetime>Mvvm.Navigation.ServiceLifetime.Scoped</ViewModelLifetime>
        <ViewModelLifetime_IsLiteral>true</ViewModelLifetime_IsLiteral>
    </AssemblyAttribute>
</ItemGroup>

Default lifetime is ServiceLifetime.Transient for View and ServiceLifetime.Scoped for ViewModel. 3. Add Navigator to your ViewModel:

public Navigator<ObservableObject> Navigator { get; }
  1. Add commands to your views(or just use Navigator from ViewModel):
<Grid>
    <Button
        Command="{Binding Navigator.NavigateByTypeCommand}"
        CommandParameter="{x:Type viewModels:BlueViewModel}"
        />
    <ContentControl Content="{Binding Navigator.CurrentView}"/>
</Grid>

Tip: you can use CommandParameter="{mvvm:Type Type=viewModels:BlueViewModel}" for WinUI/UWP/Uno platforms.

Base

The library was written as a replacement for ReactiveUI in a real project, and inherits some concepts from it, excluding reactivity.
If you have the same task, then the changes are as follows:

  • Replace RoutingState with Navigator
  • Replace IScreen with INavigable
  • Replace ReactiveUserControl with UserControl
  • Replace ReactiveWindow with Window
  • Replace RoutedViewHost and ViewModelViewHost with ContentControl
  • Use mvvm:Navigation.ViewModel and mvvm:Navigation.Navigator(includes ServiceProvider) attached dependency properties.
  • Or just bind like this <ContentControl Content="{Binding Navigator.CurrentView}"/>

Support

Priority place for bugs: https://github.com/HavenDV/Mvvm.Navigation/issues
Priority place for ideas and general questions: https://github.com/HavenDV/Mvvm.Navigation/discussions
I also have a Discord support channel:
https://discord.gg/g8u2t9dKgE