{"id":14986424,"url":"https://github.com/usausa/smart-net-navigation","last_synced_at":"2025-04-11T20:32:46.522Z","repository":{"id":38206148,"uuid":"52414813","full_name":"usausa/Smart-Net-Navigation","owner":"usausa","description":"Navigation library for WPF/MAUI/Windows Forms.","archived":false,"fork":false,"pushed_at":"2024-04-17T01:20:09.000Z","size":2610,"stargazers_count":19,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-05-16T11:25:57.163Z","etag":null,"topics":["csharp","dotnet","dotnet-core","dotnetcore","maui","navigation","smart","windows-forms","wpf","xamarin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/usausa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-24T04:41:29.000Z","updated_at":"2024-06-14T11:47:34.269Z","dependencies_parsed_at":"2023-02-09T22:01:01.300Z","dependency_job_id":"30e50cfb-e7a7-4761-b913-17019242ed13","html_url":"https://github.com/usausa/Smart-Net-Navigation","commit_stats":{"total_commits":529,"total_committers":1,"mean_commits":529.0,"dds":0.0,"last_synced_commit":"d639de35d59c14caaff10f195a9c070c3b5c9981"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Navigation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Navigation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Navigation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usausa%2FSmart-Net-Navigation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usausa","download_url":"https://codeload.github.com/usausa/Smart-Net-Navigation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248476607,"owners_count":21110321,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","dotnet-core","dotnetcore","maui","navigation","smart","windows-forms","wpf","xamarin"],"created_at":"2024-09-24T14:12:51.036Z","updated_at":"2025-04-11T20:32:46.508Z","avatar_url":"https://github.com/usausa.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Smart.Navigation .NET - navigation library for .NET\n\n[![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation/)\n\n## What is this ?\n\n* Navigation by control switching.\n* Navigationg to view by id.\n* Multiplatform support.\n* MVVM support with WPF and Xamarin.Forms provider.\n* Parameter support between target.\n* Stacked navigation support.\n* Lifecycle event support.\n* Cancel event support.\n* Plugin support.\n* Library integration support.\n\n### Usage example\n\n```csharp\n// Config Navigator\nnavigator = new NavigatorConfig()\n    .UseFormsNavigationProvider()\n    .UseResolver(resolver)\n    .UseIdViewMapper(m =\u003e m.AutoRegister(Assembly.GetExecutingAssembly().ExportedTypes))\n    .ToNavigator();\n\n// Navigate to view\nnavigator.Forward(ViewId.Menu);\n```\n\n## NuGet\n\n| Package | Note |\n|-|-|\n| [![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation/) | Core libyrary |\n| [![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.Resolver.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation.Resolver/) | Smart.Resolver integration |\n| [![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.Maui.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation.Maui/) | MAUI provider |\n| [![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.Windows.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation.Windows/) | WPF provider |\n| [![NuGet](https://img.shields.io/nuget/v/Usa.Smart.Navigation.Windows.Forms.svg)](https://www.nuget.org/packages/Usa.Smart.Navigation.Windows.Forms/) | Windows Forms provider |\n\n## Supported platform\n\n### Windows Forms\n\n``Control`` is a container and ``Control`` is a view.\n\n```csharp\nnavigator = new NavigatorConfig()\n    .UseControlNavigationProvider(ContainerPanel)\n    .ToNavigator();\n```\n\n### WPF\n\n``ContentControl`` is a container and ``Control`` is a view.\n\n```csharp\nnavigator = new NavigatorConfig()\n    .UseWindowsNavigationProvider()\n    .ToNavigator();\n```\n\n```xml\n\u003cContentControl\u003e\n    \u003ci:Interaction.Behaviors\u003e\n        \u003cnavigation:NavigationContainerBehavior Navigator=\"{Binding Navigator}\"/\u003e\n    \u003c/i:Interaction.Behaviors\u003e\n\u003c/ContentControl\u003e\n```\n\n### Xamarin.Forms\n\n``ContentView`` is a container and ``View`` is a view.\n\n```csharp\nnavigator = new NavigatorConfig()\n    .UseFormsNavigationProvider()\n    .ToNavigator();\n```\n\n```xml\n\u003cContentView\u003e\n    \u003cContentView.Behaviors\u003e\n        \u003cnavigation:NavigationContainerBehavior Navigator=\"{Binding Navigator}\" /\u003e\n    \u003c/ContentView.Behaviors\u003e\n\u003c/ContentView\u003e\n```\n\n### Create custom platform support\n\nImplement the following interface.\n\n```csharp\npublic interface INavigationProvider\n{\n    // Resolve target(DataContext/BindingContext) from view\n    object ResolveTarget(object view);\n\n    // Add view to container\n    void OpenView(object view);\n\n    // Remove view from container and dispose\n    void CloseView(object view);\n\n    // Restore view from stack\n    void ActiveView(object view, object parameter);\n\n    // Deactive view\n    object DeactiveView(object view);\n}\n```\n\n## View mapper\n\n### Id to Type dictionary mapping\n\n```csharp\n// Configuration method\nNavigatorConfig UseIdViewMapper(Action\u003cIIdViewRegister\u003e action);\n\n// Register interface\npublic interface IIdViewRegister\n{\n    void Register(object id, Type type);\n}\n\n// Auto register extension\nvoid AutoRegister(IEnumerable\u003cType\u003e types);\n```\n\n```csharp\n// Usage\npublic enum ViewId\n{\n    ViewList,\n    ViewDetailNew,\n    ViewDetailUpdate\n}\n\n[View(ViewId.ViewList)]\npublic sealed class ViewList\n{\n}\n\n[View(ViewId.ViewDetailNew)]\n[View(ViewId.ViewDetailUpdate)]\npublic sealed class ViewDetail\n{\n}\n\n// config\nvar navigator = new NavigatorConfig()\n    .UseSomeProvider()\n    .UseIdViewMapper(m =\u003e m.AutoRegister(Assembly.GetExecutingAssembly().ExportedTypes))\n    .ToNavigator();\n\n// navigation\nnavigator.Forward(ViewId.ViewList);\n\n```\n\n### Direct type mapping (default)\n\n```csharp\n// Configuration method\nNavigatorConfig UseDirectViewMapper();\n```\n\n```csharp\n// config\nvar navigator = new NavigatorConfig()\n    .UseSomeProvider()\n    .UseDirectViewMapper()\n    .ToNavigator();\n\n// navigation\nnavigator.Forward(typeof(View1));\n\n```\n\n### Path mapping\n\n```csharp\n// Configuration method\nNavigatorConfig UsePathViewMapper(Action\u003cPathViewMapperOptions\u003e action)\n```\n\n```csharp\n// Usage\nnamespace Example.Views\n{\n    public sealed class ParentView\n    {\n    }\n}\n\nnamespace Example.Views.Children\n{\n    public sealed class Child1View\n    {\n    }\n\n    public sealed class Child2View\n    {\n    }\n}\n\n// config\nvar navigator = new NavigatorConfig()\n    .UseMockFormProvider()\n    .UsePathViewMapper(option =\u003e\n    {\n        option.Root = \"Example.Views\";\n        option.Suffix = \"View\";\n        option.AddAssembly(Assembly.GetExecutingAssembly());\n    })\n    .ToNavigator();\n\n// navigation\nnavigator.Forward(\"/Parent\");\nnavigator.Forward(\"/Children/Child1\");\nnavigator.Forward(\"Child2\");\nnavigator.Forward(\"../Parent\");\nnavigator.Forward(\"Children/Child2\");\n```\n\n## Navigation\n\n### Forward\n\nNon stacked navigation.\n\n```csharp\nbool Forward(object id);\n\nbool Forward(object id, INavigationParameter parameter);\n\nTask\u003cbool\u003e ForwardAsync(object id);\n\nTask\u003cbool\u003e ForwardAsync(object id, INavigationParameter parameter);\n```\n\n### Push\n\nStacked navigation.\n\n```csharp\nbool Push(object id);\n\nbool Push(object id, INavigationParameter parameter);\n\nTask\u003cbool\u003e PushAsync(object id);\n\nTask\u003cbool\u003e PushAsync(object id, INavigationParameter parameter);\n```\n\n### Pop\n\nPop stack navigation.\n\n```csharp\nbool Pop();\n\nbool Pop(INavigationParameter parameter);\n\nbool Pop(int level);\n\nbool Pop(int level, INavigationParameter parameter);\n\nTask\u003cbool\u003e PopAsync();\n\nTask\u003cbool\u003e PopAsync(INavigationParameter parameter);\n\nTask\u003cbool\u003e PopAsync(int level);\n\nTask\u003cbool\u003e PopAsync(int level, INavigationParameter parameter);\n```\n\n### PopAndForward\n\nPop with Forward navigation.\n\n```csharp\nbool PopAndForward(object id);\n\nbool PopAndForward(object id, int level);\n\nbool PopAllAndForward(object id);\n\nbool PopAndForward(object id, INavigationParameter parameter);\n\nbool PopAndForward(object id, int level, INavigationParameter parameter);\n\nbool PopAllAndForward(object id, INavigationParameter parameter);\n\nTask\u003cbool\u003e PopAndForwardAsync(object id);\n\nTask\u003cbool\u003e PopAndForwardAsync(object id, int level);\n\nTask\u003cbool\u003e PopAllAndForwardAsync(object id);\n\nTask\u003cbool\u003e PopAndForwardAsync(object id, INavigationParameter parameter);\n\nTask\u003cbool\u003e PopAndForwardAsync(object id, int level, INavigationParameter parameter);\n\nTask\u003cbool\u003e PopAllAndForwardAsync(object id, INavigationParameter parameter);\n```\n\n### Create custom navigation\n\nImplement the following interface to create custom navigation.\n\n```csharp\npublic interface INavigationStrategy\n{\n    // Initialize\n    StragtegyResult Initialize(INavigationController controller);\n\n    // Resolve next view\n    object ResolveToView(INavigationController controller);\n\n    // Stack update\n    void UpdateStack(INavigationController controller, object toView);\n}\n```\n\n## Navigator property\n\n```csharp\npublic interface INavigator\n{\n    // Stack count\n    int StackedCount { get; }\n\n    // Current view id\n    object CurrentViewId { get; }\n\n    // Current view instance\n    object CurrentView { get; }\n\n    // Current target(DataContext/BindingContext or view itself) instance\n    object CurrentTarget { get; }\n\n    // Navigating status\n    bool Executing { get; }\n}\n```\n\n## Event\n\n### INavigationEventSupport\n\n```csharp\npublic interface INavigationEventSupport\n{\n    // From page event berfore stack changed\n    void OnNavigatingFrom(INavigationContext context);\n\n    // To page event berfore stack changed\n    void OnNavigatingTo(INavigationContext context);\n\n    // To page event after stack changed\n    void OnNavigatedTo(INavigationContext context);\n}\n```\n\n``INavigationContext`` has navigation information.\n\n```csharp\npublic interface INavigationContext\n{\n    object FromId { get; }\n\n    object ToId { get; }\n\n    NavigationAttributes Attribute { get; }\n\n    INavigationParameter Parameter { get; }\n}\n```\n\n``INavigationParameter`` is navigation parameteter store.\n\n```csharp\npublic interface INavigationParameter\n{\n    T GetValue\u003cT\u003e(string key);\n\n    T GetValue\u003cT\u003e();\n\n    T GetValueOrDefault\u003cT\u003e(string key);\n\n    T GetValueOrDefault\u003cT\u003e();\n\n    T GetValueOr\u003cT\u003e(string key, T defaultValue);\n\n    T GetValueOr\u003cT\u003e(T defaultValue);\n}\n```\n\n``NavigationAttributes`` has the following extension methods.\n\n```csharp\npublic static class NavigationAttributesExtensions\n{\n    public static bool IsStacked(this NavigationAttributes attributes);\n\n    public static bool IsRestore(this NavigationAttributes attributes);\n}\n```\n\n### INavigator events\n\n```csharp\npublic interface INavigator\n{\n    // Cancel confirm event\n    event EventHandler\u003cConfirmEventArgs\u003e Confirm;\n\n    // Navigating event before stack changed\n    event EventHandler\u003cNavigationEventArgs\u003e Navigating;\n\n    // Navigating event after stack changed\n    event EventHandler\u003cNavigationEventArgs\u003e Navigated;\n\n    // Navigator exit event\n    event EventHandler\u003cEventArgs\u003e Exited;\n\n    // Navigation executing changed event\n    event EventHandler\u003cEventArgs\u003e ExecutingChanged;\n}\n```\n\n``ConfirmEventArgs`` is ``CancelEventArgs`` with ``INavigationContext``.\n\n```csharp\npublic sealed class ConfirmEventArgs : CancelEventArgs\n{\n    public INavigationContext Context { get; }\n}\n```\n\n``NavigationEventArgs`` has ``INavigationContext`` and view instance information.\n\n```csharp\npublic sealed class NavigationEventArgs : EventArgs\n{\n    public INavigationContext Context { get; }\n\n    public object FromView { get; }\n\n    public object FromTarget { get; }\n\n    public object ToView { get; }\n\n    public object ToTarget { get; }\n}\n```\n\n## Supported interfaces\n\n### IConfirmRequest/IConfirmRequestAsync\n\nCancel when false is returned.\n\n```csharp\npublic interface IConfirmRequest\n{\n    bool CanNavigate(INavigationContext context);\n}\n```\n\n```csharp\npublic interface IConfirmRequestAsync\n{\n    Task\u003cbool\u003e CanNavigateAsync(INavigationContext context);\n}\n```\n\n### INotifySupport/INotifySupportAsync\n\nNavigator external notification reception interface.\n\n```csharp\npublic interface INotifySupport\n{\n    void NavigatorNotify(object parameter);\n}\n\npublic interface INotifySupport\u003cin T\u003e\n{\n    void NavigatorNotify(T parameter);\n}\n\npublic interface INotifySupportAsync\n{\n    Task NavigatorNotifyAsync(object parameter);\n}\n\npublic interface INotifySupportAsync\u003cin T\u003e\n{\n    Task NavigatorNotifyAsync(T parameter);\n}\n```\n\nNotification method is as follows.\n\n```csharp\n// Usage\nnavigator.Notyfy(parameter);\n\n// Usage(Async)\nawait navigator.NotyfyAsync(parameter);\n```\n\n### INavigatorAware\n\nNavigator is injected.\n\n```csharp\npublic interface INavigatorAware\n{\n    INavigator Navigator { get; set; }\n}\n```\n\n## Plugins\n\n### Parameter plugin\n\nPrevious parameter is set next.\n\n```csharp\npublic sealed class View1\n{\n    [Parameter]\n    public int IntParameter { get; set; }\n}\n\npublic sealed class View2\n{\n    [Parameter]\n    public int IntParameter { get; set; }\n}\n\n// Test\nnavigator.Forward(typeof(View1));\n\nvar view1 = (View1)navigator.CurrentView;\nview1.IntParameter = 123;\n\nnavigator.Forward(typeof(View2));\n\nvar view2 = (View2)navigator.CurrentView;\nAssert.Equal(123, view2.IntParameter);\n```\n\n* Set to property with same name.\n* Even if the name of the property is different, it can be specified by attribute.\n* I/O direction can be limited by ``Directions.Import``/``Directions.Export``.\n* When different types are converted by IConverter.\n\n### Scope plugin\n\nInject object that exist between scopes.\n\n```csharp\npublic sealed class ScopeData : IInitializable, IDisposable\n{\n...\n}\n\npublic sealed class Data1View\n{\n}\n\npublic sealed class Data2View\n{\n    [Scope]\n    public ScopeData Data { get; set; }\n}\n\npublic sealed class Data3View\n{\n    [Scope]\n    public ScopeData Data { get; set; }\n}\n\n// Test\nnavigator.Forward(typeof(Data1View));\n\nnavigator.Forward(typeof(Data2View)); // ScopeDate create and initialized\nvar view2 = (Data2View)navigator.CurrentView;\n\nnavigator.Forward(typeof(Data3View));\nvar view3 = (Data3View)navigator.CurrentView;\n\nAssert.Equal(view3.Data, view2.Data);\n\nnavigator.Forward(typeof(Data1View)); // ScopeData disposed\n\n```\n\n* Set to property with same name.\n* Even if the name of the property is different, it can be specified by attribute.\n* Supports ``IInitializable`` and ``IDisposable`` lifecycle events.\n\n### Create custom plugin\n\nImplement the following interface and register to NavigatorConfig.\n\n```csharp\npublic interface IPlugin\n{\n    // Process when view created\n    void OnCreate(IPluginContext context, object view, object target);\n\n    // Process when view closed\n    void OnClose(IPluginContext context, object view, object target);\n\n    // Process before stack is changed\n    void OnNavigatingFrom(IPluginContext context, object view, object target);\n\n    // Process before stack is changed\n    void OnNavigatingTo(IPluginContext context, object view, object target);\n\n    // Process after stack is changed\n    void OnNavigatedTo(IPluginContext context, object view, object target);\n}\n```\n\nIPluginContext is data store for plugin.\n\n```csharp\npublic interface IPluginContext\n{\n    void Save\u003cT\u003e(Type type, T value);\n\n    T Load\u003cT\u003e(Type type);\n\n    T LoadOr\u003cT\u003e(Type type, T defaultValue);\n\n    T LoadOr\u003cT\u003e(Type type, Func\u003cT\u003e defaultValueFactory);\n}\n```\n\n## Library integration\n\n### IActivator\n\n* Interface is used for object creation.\n* Default implementation is ``Activator.CreateInstance()``.\n* Customizable by creating the following implementation.\n\n```csharp\npublic interface IActivator\n{\n    object Resolve(Type type);\n}\n```\n\n``Usa.Smart.Navigation.Resolver`` provides an implementation of ``IActivator`` using ``Usa.Smart.Resolver``.\n\n```csharp\n// Usage\n\n// Config Resolver\nvar resolver = CreateResolver();\n\n// Config Navigator\nnavigator = new NavigatorConfig()\n    .UseSomeProvider()\n    .UseResolver(resolver)\n    .ToNavigator();\n```\n\n### IConverter\n\n* Interface is used for type conversion.\n* Default implementation uses ``Smart.Converter.IObjectConverter``.\n* Customizable by creating the following implementation.\n\n```csharp\npublic interface IConverter\n{\n    object Convert(object value, Type type);\n}\n```\n\n## Link\n\n* [Smart.Resolver](https://github.com/usausa/Smart-Net-Resolver)\n\n## Future\n\n* Animation support required (・ω・)?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusausa%2Fsmart-net-navigation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusausa%2Fsmart-net-navigation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusausa%2Fsmart-net-navigation/lists"}