using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using Tango.Core; using Tango.SharedUI.Controls; namespace Tango.FSE.Common.Navigation { public abstract class ModularNavigationManager : ExtendedObject, IModularNavigationNavigationManager { private FrameworkElement _navigationControlParent; private NavigationControl _navigationControl; private Stack _history; private T _currentView; public T CurrentView { get { return _currentView; } protected set { _currentView = value; RaisePropertyChangedAuto(); } } public bool CanNavigateBack { get { return _history.Count > 0; } } public ModularNavigationManager(FrameworkElement navigationControlParent) { _history = new Stack(); _navigationControlParent = navigationControlParent; _navigationControlParent.RegisterForLoadedOrNow((_, __) => { _navigationControl = _navigationControlParent.FindChildOffline(); }); } public Task NavigateTo(T view, bool pushToHistory = true) { return NavigateToInternal(view, null, pushToHistory); } public Task NavigateTo(T view, TPass objectToPass, bool pushToHistory = true) { return NavigateToInternal(view, objectToPass, pushToHistory); } private Task NavigateToInternal(T view, TPass objectToPass, bool pushToHistory) { LogManager.Log($"Navigating to {view}..."); TaskCompletionSource completion = new TaskCompletionSource(); var fromVM = _navigationControl.SelectedElement.DataContext as FSEViewModel; var toVM = _navigationControl.GetElement(view.ToString()).DataContext as FSEViewModel; if (fromVM != toVM) { fromVM.OnBeforeNavigatedFrom(); toVM.OnBeforeNavigatedTo(); if (toVM is INavigationObjectReceiver && objectToPass != null) { (toVM as INavigationObjectReceiver).OnNavigatedToWithObject(objectToPass); } _navigationControl.NavigateTo(view.ToString(), () => { if (pushToHistory) { _history.Push(CurrentView); DistinctHistory(); RaisePropertyChanged(nameof(CanNavigateBack)); } CurrentView = view; fromVM.OnNavigatedFrom(); toVM.OnNavigatedTo(); completion.SetResult(true); }); } else { completion.SetResult(true); } return completion.Task; } public async Task NavigateBack() { if (CanNavigateBack) { var toView = _history.Peek(); var fromVM = _navigationControl.GetElement(CurrentView.ToString()).DataContext as FSEViewModel; if (fromVM is INavigationBlocker) { if (!await (fromVM as INavigationBlocker).OnNavigateBackRequest()) { return false; } } _history.Pop(); RaisePropertyChanged(nameof(CanNavigateBack)); await NavigateTo(toView, false); return true; } else { return false; } } private void DistinctHistory() { var list = _history.Distinct().ToList(); list.Reverse(); _history.Clear(); foreach (var item in list) { _history.Push(item); } RaisePropertyChanged(nameof(CanNavigateBack)); } public async Task GetCurrentViewModel() { if (_navigationControl == null) { await Task.Factory.StartNew(() => { while (_navigationControl == null) { Thread.Sleep(10); } }); } return _navigationControl.GetElement(CurrentView.ToString()).DataContext as FSEViewModel; } public async void RaiseOnBeforeNavigatedToFirst() { var currentVM = await GetCurrentViewModel(); if (currentVM != null && _navigationControl.Elements.Count > 0 && currentVM == _navigationControl.Elements.First().DataContext) { currentVM.OnBeforeNavigatedTo(); } } public async void RaiseOnNavigatedToFirst() { var currentVM = await GetCurrentViewModel(); if (currentVM != null && _navigationControl.Elements.Count > 0 && currentVM == _navigationControl.Elements.First().DataContext) { currentVM.OnNavigatedTo(); } } } }