From 2c8da378c82e5181f0566a564de529ab7ef96f4f Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Thu, 23 Aug 2018 09:45:01 +0300 Subject: Improvements to machine studio view models and navigation system. Improvements to tech board selection and edit modes handling. --- .../Navigation/DefaultNavigationManager.cs | 369 ++++++++++++++++++++- 1 file changed, 364 insertions(+), 5 deletions(-) (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Navigation') diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Navigation/DefaultNavigationManager.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Navigation/DefaultNavigationManager.cs index 092b958cc..899ba846e 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Navigation/DefaultNavigationManager.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Navigation/DefaultNavigationManager.cs @@ -3,8 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.Commands; using Tango.MachineStudio.Common; +using Tango.MachineStudio.Common.Modules; using Tango.MachineStudio.Common.Navigation; +using Tango.MachineStudio.Common.Threading; +using Tango.SharedUI.Controls; namespace Tango.MachineStudio.UI.Navigation { @@ -12,18 +17,372 @@ namespace Tango.MachineStudio.UI.Navigation /// Represents the Machine Studio default Navigation Manager. /// /// - public class DefaultNavigationManager : INavigationManager + public class DefaultNavigationManager : ExtendedObject, INavigationManager { + private event Action NavigationCycleCompleted; + + private IDispatcherProvider _dispatcherProvider; + private IStudioModuleLoader _moduleLoader; + private Object _currentVM; + private String _lastFullPath; + private bool _preventHistory; + private bool _navigating_back; + + private Stack _navigationHistory; + + /// + /// Gets the current view model. + /// + public StudioViewModel CurrentVM + { + get { return _currentVM as StudioViewModel; } + } + + private IStudioModule _currentModule; + /// + /// Gets or sets the current module. + /// + public IStudioModule CurrentModule + { + get { return _currentModule; } + private set { _currentModule = value; RaisePropertyChangedAuto(); } + } + + /// + /// Navigates to the previous view. + /// + public RelayCommand NavigateBackCommand { get; private set; } + + /// + /// Navigates to the specified full path in command parameter. + /// + public RelayCommand NavigateToCommand { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The module loader. + public DefaultNavigationManager(IStudioModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider) + { + _navigationHistory = new Stack(); + _moduleLoader = moduleLoader; + + NavigateToCommand = new RelayCommand(async (x) => await NavigateTo(x)); + NavigateBackCommand = new RelayCommand(async () => await NavigateBack()); + + _dispatcherProvider = dispatcherProvider; + } + /// - /// Navigates to the specified view. + /// Navigates to the specified PPC view. /// /// The view. - public void NavigateTo(NavigationView view) + public Task NavigateTo(NavigationView view, bool pushToHistory = true) { - MainWindow.Instance.Dispatcher.Invoke(() => + LogManager.Log($"Navigating to: {view.ToString()}..."); + + _dispatcherProvider.Invoke(() => { - MainWindow.Instance.TransitionControl.NavigateTo(view.ToString()); + MainWindow.Instance.NavigationControl.NavigateTo(view.ToString()); }); + + return Task.FromResult(true); + } + + /// + /// Navigates to the specified PPC view with the specified receive object. + /// + /// The view. + /// + /// + /// + public Task NavigateWithObject(NavigationView view, TPass obj, bool pushToHistory = true) + { + LogManager.Log($"Navigating to: {view.ToString()}, with object {typeof(TPass).Name}..."); + MainWindow.Instance.NavigationControl.NavigateTo(view.ToString()); + INavigationObjectReceiver receiver = MainWindow.Instance.NavigationControl.Elements.FirstOrDefault(x => (x.GetType().Name == view.ToString() || NavigationControl.GetNavigationName(x) == view.ToString()) && x.DataContext is INavigationObjectReceiver).DataContext as INavigationObjectReceiver; + + if (receiver != null) + { + receiver.OnNavigatedToWithObject(obj); + } + + return Task.FromResult(true); + } + + /// + /// Navigates to the specified module. + /// + /// + public Task NavigateTo(bool pushToHistory = true) where T : IStudioModule + { + return NavigateTo(typeof(T)); + } + + /// + /// Navigates to the specified module using the view path (e.g MainView.JobsView). + /// + /// + /// The view path. + public Task NavigateTo(string viewPath, bool pushToHistory = true) where T : IStudioModule + { + return NavigateTo(pushToHistory, viewPath.Split('.')); + } + + /// + /// Navigates to the specified module using the view path (e.g MainView,JobsView). + /// This method makes it easy to do stuff like NavigateTo(nameof(MainView),nameof(JobsView)); + /// + /// + /// The view path. + public Task NavigateTo(bool pushToHistory = true, params String[] viewPath) where T : IStudioModule + { + return NavigateTo(typeof(T), pushToHistory, viewPath); + } + + /// + /// Navigates to the specified module and view by full path (e.g Jobs.JobsView). + /// + /// The full path. + public async Task NavigateTo(String fullPath, bool pushToHistory = true) + { + String[] path = fullPath.Split('.'); + var module = _moduleLoader.UserModules.SingleOrDefault(x => x.GetType().Name == path[0] || x.Name == path[0]); + + if (path.Length == 1 && path[0] == CurrentModule.Name) return true; + + LogManager.Log($"Navigating to: {fullPath}..."); + + var fromVM = _currentVM; + + if (_currentVM != null && _currentVM is INavigationBlocker) + { + if (_navigating_back) + { + if (!await (_currentVM as INavigationBlocker).OnNavigateBackRequest()) + { + return false; + } + } + else + { + if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest()) + { + return false; + } + } + } + + if (pushToHistory && _lastFullPath != null && !_preventHistory) + { + _navigationHistory.Push(_lastFullPath); + RaisePropertyChanged(nameof(CanNavigateBack)); + } + + _lastFullPath = fullPath; + + MainWindow.Instance.NavigationControl.NavigateTo(NavigationView.MainView.ToString()); + var navigationControl = MachineStudio.UI.Views.MainView.Instance.NavigationControl; + CurrentModule = module; + var moduleView = navigationControl.NavigateTo(module.Name); + + _currentVM = moduleView.DataContext; + + if (path.Length > 1) + { + var moduleNavigation = moduleView.FindChildOffline(); + + moduleNavigation.RegisterForLoadedOrNow(async (x, e) => + { + foreach (var view in path.Skip(1)) + { + await Task.Delay(100); + var v = moduleNavigation.NavigateTo(view); + + if (v != null) + { + _currentVM = v.DataContext; + + if (view != path.Last()) + { + moduleNavigation = v.FindChildOffline(); + } + } + else + { + throw LogManager.Log(new ArgumentNullException("Could not navigate to " + fullPath)); + } + } + + NavigationCycleCompleted?.Invoke(fromVM, _currentVM); + }); + } + + return true; + } + + /// + /// Navigates for result. + /// + /// The type of the module. + /// The type of the view. + /// The type of the result. + /// The type of the object. + /// The object. + /// if set to true [push to history]. + /// + public Task NavigateForResult(TObject obj, bool pushToHistory = true) + where TModule : IStudioModule + { + TaskCompletionSource source = new TaskCompletionSource(); + + var fromVM = _currentVM; + Object toVM = null; + + + Action handler = null; + + handler = (from, to) => + { + if (toVM == null) + { + toVM = to; + if (toVM is INavigationResultProvider) + { + (toVM as INavigationResultProvider).OnNavigationObjectReceived(obj); + } + } + else + { + if (to == fromVM && from == toVM) + { + if (from is INavigationResultProvider) + { + source.SetResult((from as INavigationResultProvider).GetNavigationResult()); + } + } + + NavigationCycleCompleted -= handler; + } + }; + + NavigationCycleCompleted += handler; + + NavigateTo(typeof(TView).Name, pushToHistory); + + return source.Task; + } + + /// + /// Navigates to the specified module and view with the specified object. + /// + /// The type of the module. + /// The type of the view. + /// The type of the pass. + /// The object. + /// if set to true [push to history]. + /// + public Task NavigateWithObject(TPass obj, bool pushToHistory = true) where TModule : IStudioModule + { + TaskCompletionSource source = new TaskCompletionSource(); + + Action handler = null; + + handler = (from, to) => + { + if (to is INavigationObjectReceiver) + { + (to as INavigationObjectReceiver).OnNavigatedToWithObject(obj); + } + + NavigationCycleCompleted -= handler; + }; + + NavigationCycleCompleted += handler; + + NavigateTo(typeof(TView).Name, pushToHistory); + + return source.Task; + } + + private Task NavigateTo(Type moduleType, bool pushToHistory = true, params String[] viewPath) + { + if (viewPath != null && viewPath.Length > 0) + { + return NavigateTo(moduleType.Name + "." + String.Join(".", viewPath), pushToHistory); + } + else + { + return NavigateTo(moduleType.Name, pushToHistory); + } + } + + /// + /// Gets a value indicating whether the navigation system is able to navigate to the previous view. + /// + public bool CanNavigateBack + { + get { return _navigationHistory.Count > 0; } + } + + /// + /// Navigates to the previous view if is true. + /// + public async Task NavigateBack() + { + LogManager.Log("Navigating back..."); + + _navigating_back = true; + + String first = _navigationHistory.Pop(); + _preventHistory = true; + + + if (await NavigateTo(first)) + { + RaisePropertyChanged(nameof(CanNavigateBack)); + _preventHistory = false; + _navigating_back = false; + return true; + } + else + { + _navigationHistory.Push(first); + _preventHistory = false; + _navigating_back = false; + RaisePropertyChanged(nameof(CanNavigateBack)); + return false; + } + } + + /// + /// Clears the navigation back history. + /// + public void ClearHistory() + { + LogManager.Log("Navigation history cleared."); + _navigationHistory.Clear(); + RaisePropertyChanged(nameof(CanNavigateBack)); + } + + /// + /// Clears the navigation back history except the specified view type. + /// + /// + public void ClearHistoryExcept() + { + LogManager.Log($"Navigation history cleared except for {typeof(T).Name}."); + + var history_list = _navigationHistory.ToList(); + history_list = history_list.Where(x => x.Contains(typeof(T).Name)).Distinct().ToList(); + _navigationHistory.Clear(); + + foreach (var item in history_list) + { + _navigationHistory.Push(item); + } + + RaisePropertyChanged(nameof(CanNavigateBack)); } } } -- cgit v1.3.1