Skip to content

usausa/Smart-Net-Navigation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Smart.Navigation .NET - navigation library for .NET

NuGet

What is this ?

  • Navigation by control switching.
  • Navigationg to view by id.
  • Multiplatform support.
  • MVVM support with WPF and Xamarin.Forms provider.
  • Parameter support between target.
  • Stacked navigation support.
  • Lifecycle event support.
  • Cancel event support.
  • Plugin support.
  • Library integration support.

Usage example

// Config Navigator
navigator = new NavigatorConfig()
    .UseFormsNavigationProvider()
    .UseResolver(resolver)
    .UseIdViewMapper(m => m.AutoRegister(Assembly.GetExecutingAssembly().ExportedTypes))
    .ToNavigator();

// Navigate to view
navigator.Forward(ViewId.Menu);

Example of use in MAUI project

NuGet

Package Note
NuGet Core libyrary
NuGet Smart.Resolver integration
NuGet MAUI provider
NuGet WPF provider
NuGet Windows Forms provider
NuGet Avalonia provider

Supported platform

Windows Forms

Control is a container and Control is a view.

navigator = new NavigatorConfig()
    .UseControlNavigationProvider(ContainerPanel)
    .ToNavigator();

WPF

ContentControl is a container and Control is a view.

navigator = new NavigatorConfig()
    .UseWindowsNavigationProvider()
    .ToNavigator();
<ContentControl>
    <i:Interaction.Behaviors>
        <navigation:NavigationContainerBehavior Navigator="{Binding Navigator}"/>
    </i:Interaction.Behaviors>
</ContentControl>

Xamarin.Forms

ContentView is a container and View is a view.

navigator = new NavigatorConfig()
    .UseFormsNavigationProvider()
    .ToNavigator();
<ContentView>
    <ContentView.Behaviors>
        <navigation:NavigationContainerBehavior Navigator="{Binding Navigator}" />
    </ContentView.Behaviors>
</ContentView>

Create custom platform support

Implement the following interface.

public interface INavigationProvider
{
    // Resolve target(DataContext/BindingContext) from view
    object ResolveTarget(object view);

    // Add view to container
    void OpenView(object view);

    // Remove view from container and dispose
    void CloseView(object view);

    // Restore view from stack
    void ActiveView(object view, object parameter);

    // Deactive view
    object DeactiveView(object view);
}

View mapper

Id to Type dictionary mapping

// Configuration method
NavigatorConfig UseIdViewMapper(Action<IIdViewRegister> action);

// Register interface
public interface IIdViewRegister
{
    void Register(object id, Type type);
}

// Auto register extension
void AutoRegister(IEnumerable<Type> types);
// Usage
public enum ViewId
{
    ViewList,
    ViewDetailNew,
    ViewDetailUpdate
}

[View(ViewId.ViewList)]
public sealed class ViewList
{
}

[View(ViewId.ViewDetailNew)]
[View(ViewId.ViewDetailUpdate)]
public sealed class ViewDetail
{
}

// config
var navigator = new NavigatorConfig()
    .UseSomeProvider()
    .UseIdViewMapper(m => m.AutoRegister(Assembly.GetExecutingAssembly().ExportedTypes))
    .ToNavigator();

// navigation
navigator.Forward(ViewId.ViewList);

Direct type mapping (default)

// Configuration method
NavigatorConfig UseDirectViewMapper();
// config
var navigator = new NavigatorConfig()
    .UseSomeProvider()
    .UseDirectViewMapper()
    .ToNavigator();

// navigation
navigator.Forward(typeof(View1));

Path mapping

// Configuration method
NavigatorConfig UsePathViewMapper(Action<PathViewMapperOptions> action)
// Usage
namespace Example.Views
{
    public sealed class ParentView
    {
    }
}

namespace Example.Views.Children
{
    public sealed class Child1View
    {
    }

    public sealed class Child2View
    {
    }
}

// config
var navigator = new NavigatorConfig()
    .UseMockFormProvider()
    .UsePathViewMapper(option =>
    {
        option.Root = "Example.Views";
        option.Suffix = "View";
        option.AddAssembly(Assembly.GetExecutingAssembly());
    })
    .ToNavigator();

// navigation
navigator.Forward("/Parent");
navigator.Forward("/Children/Child1");
navigator.Forward("Child2");
navigator.Forward("../Parent");
navigator.Forward("Children/Child2");

Navigation

Forward

Non stacked navigation.

bool Forward(object id);

bool Forward(object id, INavigationParameter parameter);

Task<bool> ForwardAsync(object id);

Task<bool> ForwardAsync(object id, INavigationParameter parameter);

Push

Stacked navigation.

bool Push(object id);

bool Push(object id, INavigationParameter parameter);

Task<bool> PushAsync(object id);

Task<bool> PushAsync(object id, INavigationParameter parameter);

Pop

Pop stack navigation.

bool Pop();

bool Pop(INavigationParameter parameter);

bool Pop(int level);

bool Pop(int level, INavigationParameter parameter);

Task<bool> PopAsync();

Task<bool> PopAsync(INavigationParameter parameter);

Task<bool> PopAsync(int level);

Task<bool> PopAsync(int level, INavigationParameter parameter);

PopAndForward

Pop with Forward navigation.

bool PopAndForward(object id);

bool PopAndForward(object id, int level);

bool PopAllAndForward(object id);

bool PopAndForward(object id, INavigationParameter parameter);

bool PopAndForward(object id, int level, INavigationParameter parameter);

bool PopAllAndForward(object id, INavigationParameter parameter);

Task<bool> PopAndForwardAsync(object id);

Task<bool> PopAndForwardAsync(object id, int level);

Task<bool> PopAllAndForwardAsync(object id);

Task<bool> PopAndForwardAsync(object id, INavigationParameter parameter);

Task<bool> PopAndForwardAsync(object id, int level, INavigationParameter parameter);

Task<bool> PopAllAndForwardAsync(object id, INavigationParameter parameter);

Create custom navigation

Implement the following interface to create custom navigation.

public interface INavigationStrategy
{
    // Initialize
    StragtegyResult Initialize(INavigationController controller);

    // Resolve next view
    object ResolveToView(INavigationController controller);

    // Stack update
    void UpdateStack(INavigationController controller, object toView);
}

Navigator property

public interface INavigator
{
    // Stack count
    int StackedCount { get; }

    // Current view id
    object CurrentViewId { get; }

    // Current view instance
    object CurrentView { get; }

    // Current target(DataContext/BindingContext or view itself) instance
    object CurrentTarget { get; }

    // Navigating status
    bool Executing { get; }
}

Event

INavigationEventSupport

public interface INavigationEventSupport
{
    // From page event berfore stack changed
    void OnNavigatingFrom(INavigationContext context);

    // To page event berfore stack changed
    void OnNavigatingTo(INavigationContext context);

    // To page event after stack changed
    void OnNavigatedTo(INavigationContext context);
}

INavigationContext has navigation information.

public interface INavigationContext
{
    object FromId { get; }

    object ToId { get; }

    NavigationAttributes Attribute { get; }

    INavigationParameter Parameter { get; }
}

INavigationParameter is navigation parameteter store.

public interface INavigationParameter
{
    T GetValue<T>(string key);

    T GetValue<T>();

    T GetValueOrDefault<T>(string key);

    T GetValueOrDefault<T>();

    T GetValueOr<T>(string key, T defaultValue);

    T GetValueOr<T>(T defaultValue);
}

NavigationAttributes has the following extension methods.

public static class NavigationAttributesExtensions
{
    public static bool IsStacked(this NavigationAttributes attributes);

    public static bool IsRestore(this NavigationAttributes attributes);
}

INavigator events

public interface INavigator
{
    // Cancel confirm event
    event EventHandler<ConfirmEventArgs> Confirm;

    // Navigating event before stack changed
    event EventHandler<NavigationEventArgs> Navigating;

    // Navigating event after stack changed
    event EventHandler<NavigationEventArgs> Navigated;

    // Navigator exit event
    event EventHandler<EventArgs> Exited;

    // Navigation executing changed event
    event EventHandler<EventArgs> ExecutingChanged;
}

ConfirmEventArgs is CancelEventArgs with INavigationContext.

public sealed class ConfirmEventArgs : CancelEventArgs
{
    public INavigationContext Context { get; }
}

NavigationEventArgs has INavigationContext and view instance information.

public sealed class NavigationEventArgs : EventArgs
{
    public INavigationContext Context { get; }

    public object FromView { get; }

    public object FromTarget { get; }

    public object ToView { get; }

    public object ToTarget { get; }
}

Supported interfaces

IConfirmRequest/IConfirmRequestAsync

Cancel when false is returned.

public interface IConfirmRequest
{
    bool CanNavigate(INavigationContext context);
}
public interface IConfirmRequestAsync
{
    Task<bool> CanNavigateAsync(INavigationContext context);
}

INotifySupport/INotifySupportAsync

Navigator external notification reception interface.

public interface INotifySupport
{
    void NavigatorNotify(object parameter);
}

public interface INotifySupport<in T>
{
    void NavigatorNotify(T parameter);
}

public interface INotifySupportAsync
{
    Task NavigatorNotifyAsync(object parameter);
}

public interface INotifySupportAsync<in T>
{
    Task NavigatorNotifyAsync(T parameter);
}

Notification method is as follows.

// Usage
navigator.Notyfy(parameter);

// Usage(Async)
await navigator.NotyfyAsync(parameter);

INavigatorAware

Navigator is injected.

public interface INavigatorAware
{
    INavigator Navigator { get; set; }
}

Plugins

Parameter plugin

Previous parameter is set next.

public sealed class View1
{
    [Parameter]
    public int IntParameter { get; set; }
}

public sealed class View2
{
    [Parameter]
    public int IntParameter { get; set; }
}

// Test
navigator.Forward(typeof(View1));

var view1 = (View1)navigator.CurrentView;
view1.IntParameter = 123;

navigator.Forward(typeof(View2));

var view2 = (View2)navigator.CurrentView;
Assert.Equal(123, view2.IntParameter);
  • Set to property with same name.
  • Even if the name of the property is different, it can be specified by attribute.
  • I/O direction can be limited by Directions.Import/Directions.Export.
  • When different types are converted by IConverter.

Scope plugin

Inject object that exist between scopes.

public sealed class ScopeData : IInitializable, IDisposable
{
...
}

public sealed class Data1View
{
}

public sealed class Data2View
{
    [Scope]
    public ScopeData Data { get; set; }
}

public sealed class Data3View
{
    [Scope]
    public ScopeData Data { get; set; }
}

// Test
navigator.Forward(typeof(Data1View));

navigator.Forward(typeof(Data2View)); // ScopeDate create and initialized
var view2 = (Data2View)navigator.CurrentView;

navigator.Forward(typeof(Data3View));
var view3 = (Data3View)navigator.CurrentView;

Assert.Equal(view3.Data, view2.Data);

navigator.Forward(typeof(Data1View)); // ScopeData disposed
  • Set to property with same name.
  • Even if the name of the property is different, it can be specified by attribute.
  • Supports IInitializable and IDisposable lifecycle events.

Create custom plugin

Implement the following interface and register to NavigatorConfig.

public interface IPlugin
{
    // Process when view created
    void OnCreate(IPluginContext context, object view, object target);

    // Process when view closed
    void OnClose(IPluginContext context, object view, object target);

    // Process before stack is changed
    void OnNavigatingFrom(IPluginContext context, object view, object target);

    // Process before stack is changed
    void OnNavigatingTo(IPluginContext context, object view, object target);

    // Process after stack is changed
    void OnNavigatedTo(IPluginContext context, object view, object target);
}

IPluginContext is data store for plugin.

public interface IPluginContext
{
    void Save<T>(Type type, T value);

    T Load<T>(Type type);

    T LoadOr<T>(Type type, T defaultValue);

    T LoadOr<T>(Type type, Func<T> defaultValueFactory);
}

Library integration

IActivator

  • Interface is used for object creation.
  • Default implementation is Activator.CreateInstance().
  • Customizable by creating the following implementation.
public interface IActivator
{
    object Resolve(Type type);
}

Usa.Smart.Navigation.Resolver provides an implementation of IActivator using Usa.Smart.Resolver.

// Usage

// Config Resolver
var resolver = CreateResolver();

// Config Navigator
navigator = new NavigatorConfig()
    .UseSomeProvider()
    .UseResolver(resolver)
    .ToNavigator();

IConverter

  • Interface is used for type conversion.
  • Default implementation uses Smart.Converter.IObjectConverter.
  • Customizable by creating the following implementation.
public interface IConverter
{
    object Convert(object value, Type type);
}

Link

Future

  • Animation support required (・ω・)?

About

Navigation library for WPF/MAUI/Avalonia/Windows Forms.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages