Navigation Architecture
Overview
The MepApps EFT Remittance Dashboard implements a simplified navigation architecture designed for focused workflow execution. Unlike multi-page applications, this dashboard uses a single-view pattern with embedded functionality, leveraging the MepDash module's navigation infrastructure for seamless integration within the SYSPRO environment.
Key Concepts
- Single-View Architecture: The entire application operates within a single main view
- BaseRouteableViewModel Pattern: Provides navigation capability even in single-view scenarios
- Container-Based Navigation: Leverages SYSPRO's container navigation system
- View Injection: Dynamic content loading through dependency injection
Implementation Details
Navigation Foundation
The navigation architecture is built on the BaseRouteableViewModel class, which serves as the foundation for view models that participate in navigation:
// MepApps.Dash.Ap.Rpt.EftRemittance/ViewModels/BaseRouteableViewModel.cs
public abstract class BaseRouteableViewModel : BaseViewModel, INavigationTarget
{
protected BaseRouteableViewModel()
{
}
public virtual Task NavigatedFromAsync(INavigationRequest request)
{
return Task.CompletedTask;
}
public virtual Task NavigatedToAsync(INavigationRequest request)
{
return Task.CompletedTask;
}
}
This base class implements the INavigationTarget interface from the MepDash module, enabling navigation lifecycle events even though the dashboard maintains a single-view approach.
Main View Navigation Structure
The MainViewModel serves as the navigation host, managing the primary content area:
// MepApps.Dash.Ap.Rpt.EftRemittance/ViewModels/MainViewModel.cs
public class MainViewModel : BaseRouteableViewModel
{
private object _mainContent;
public object MainContent
{
get => _mainContent;
set
{
if (_mainContent != value)
{
_mainContent = value;
OnPropertyChanged();
}
}
}
}
The MainContent property acts as a content presenter, allowing for potential future expansion while currently hosting the EftRemit_RunReportsView.
Container Integration
The navigation system integrates with SYSPRO's container infrastructure through the MainView:
// MepApps.Dash.Ap.Rpt.EftRemittance/Views/MainView.xaml.cs
public partial class MainView : UserControl
{
private readonly IContainerEvents? _events;
private readonly IContainerNavigation? _navigation;
public MainView(ISharedShellInterface sharedShellInterface,
IContainerEvents? events,
IContainerNavigation? navigation,
IMepPluginServiceHandler mepPluginServiceHandler)
{
_events = events;
_navigation = navigation;
// Container navigation is available but not actively used
// in the single-view pattern
}
}
View Initialization Flow
The navigation initialization follows this sequence:
- Service Registration: Views and ViewModels are registered as singletons
- Dependency Resolution: The DI container resolves all dependencies
- View Construction: MainView is instantiated with all required services
- ViewModel Binding: The EftRemit_RunReportsViewModel is bound to its view
- Content Assignment: The view is set as MainContent
// MepApps.Dash.Ap.Rpt.EftRemittance/ViewModels/MainViewModel.cs
public MainViewModel(Dispatcher dispatcher,
PluginSysproDataContext pluginSysproDataContext,
EftRemit_RunReportsView eftRemit_RunReportsView,
IEftRemit_RunReportsViewModel eftRemit_RunReportsViewModel)
{
_eftRemit_RunReportsView.DataContext = _eftRemit_RunReportsViewModel;
MainContent = _eftRemit_RunReportsView;
}
Examples
Example 1: Navigation State Management
While the dashboard doesn't navigate between pages, it manages navigation state for potential expansions:
public class MainViewModel : BaseRouteableViewModel
{
public override async Task NavigatedToAsync(INavigationRequest request)
{
// Handle navigation to this dashboard
// Could receive parameters from SYSPRO menu
if (request?.Parameters?.ContainsKey("PaymentNumber") == true)
{
// Pre-select a specific payment if launched with context
var paymentNumber = request.Parameters["PaymentNumber"];
// Initialize view with specific payment
}
await base.NavigatedToAsync(request);
}
}
Example 2: Future Navigation Expansion
The architecture supports adding multiple views without restructuring:
// Potential future implementation
public void NavigateToDetailView(PaymentDetail payment)
{
var detailView = _serviceProvider.GetService<PaymentDetailView>();
var detailViewModel = _serviceProvider.GetService<IPaymentDetailViewModel>();
detailViewModel.Initialize(payment);
detailView.DataContext = detailViewModel;
MainContent = detailView; // Switches the view
}
Navigation State Patterns
State Preservation
The single-view pattern naturally preserves state since views are registered as singletons:
// Services/RegisterServiceProvider.cs
serviceCollection.AddSingleton<MainViewModel>();
serviceCollection.AddSingleton<IEftRemit_RunReportsViewModel, EftRemit_RunReportsViewModel>();
serviceCollection.AddSingleton<EftRemit_RunReportsView>();
This ensures that:
- User selections persist during the session
- Filter states are maintained
- Processing status is retained
Memory Management
The singleton pattern requires careful memory management:
public override Task NavigatedFromAsync(INavigationRequest request)
{
// Clean up any subscriptions or resources
// This is called when navigating away from the dashboard
return base.NavigatedFromAsync(request);
}
Navigation Guards and Validation
While not explicitly implemented, the architecture supports navigation guards:
public override async Task<bool> CanNavigateFromAsync()
{
if (HasUnsavedChanges())
{
var result = await ShowConfirmationDialog("Unsaved changes will be lost. Continue?");
return result;
}
return true;
}
Integration with SYSPRO Navigation
The dashboard integrates with SYSPRO's navigation through:
- Menu Integration: Launched from SYSPRO menu system
- Container Events: Responds to SYSPRO container events
- Navigation Context: Can receive parameters from SYSPRO context
- Back Navigation: Handled by SYSPRO container
Best Practices
- Singleton Services: Use singleton registration for views and view models
- State Management: Implement proper cleanup in NavigatedFromAsync
- Parameter Handling: Always validate navigation parameters
- Error Boundaries: Implement error handling in navigation methods
- Memory Leaks: Dispose of event subscriptions when navigating away
Common Pitfalls
- Not handling null navigation parameters
- Forgetting to call base navigation methods
- Memory leaks from event subscriptions
- Not preserving state when required
Related Documentation
Summary
The EFT Remittance Dashboard implements a streamlined navigation architecture optimized for single-purpose workflow execution. While maintaining compatibility with the full MepDash navigation infrastructure, it focuses on providing a stable, state-preserving environment for remittance processing operations. The architecture is extensible, allowing for future multi-view scenarios while maintaining the current simplicity and efficiency.