Navigation.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System;
  2. using System.Diagnostics.Tracing;
  3. using Avalonia.Layout;
  4. using CommunityToolkit.Mvvm.ComponentModel;
  5. using DialogHostAvalonia;
  6. using InABox.Avalonia.Components;
  7. using InABox.Avalonia.Router;
  8. namespace InABox.Avalonia;
  9. public interface IViewModelBase
  10. {
  11. Task Activate();
  12. Task Deactivate();
  13. bool OnBackButtonPressed();
  14. bool BackButtonVisible { get; set; }
  15. bool ProgressVisible { get; set; }
  16. AvaloniaMenuItemCollection PrimaryMenu { get; set; }
  17. AvaloniaMenuItemCollection SecondaryMenu { get; set; }
  18. }
  19. public interface IPopupViewModel
  20. {
  21. bool IsClosed { get; }
  22. }
  23. /// <summary>
  24. /// Indicates that this view model can be a module or a popup.
  25. /// </summary>
  26. public interface IDualFunctionViewModel : IPopupViewModel, IViewModelBase
  27. {
  28. bool IsPopup { get; set; }
  29. }
  30. public interface IAlignedPopup
  31. {
  32. HorizontalAlignment HorizontalAlignment { get; }
  33. VerticalAlignment VerticalAlignment { get; }
  34. }
  35. public interface IPopupViewModel<TResult> : IPopupViewModel
  36. {
  37. TResult? GetResult();
  38. }
  39. public static class Navigation
  40. {
  41. private static readonly HistoryRouter<IViewModelBase> _router;
  42. static Navigation()
  43. {
  44. _router = new HistoryRouter<IViewModelBase>(x => Activator.CreateInstance(x) as IViewModelBase);
  45. _router.CurrentViewModelChanging += (@base, direction) => CurrentViewModelChanging?.Invoke(@base, direction);
  46. _router.CurrentViewModelChanged += @base => CurrentViewModelChanged?.Invoke(@base);
  47. }
  48. public static void Back()
  49. {
  50. _router.Back();
  51. }
  52. public static void Navigate<T>(Action<T>? configure = null) where T : IViewModelBase
  53. {
  54. _router.GoTo<T>(configure);
  55. }
  56. public static async Task<object?> Popup<T>(Action<T>? configure = null, bool canTapAway = true)
  57. where T : IViewModelBase, IPopupViewModel
  58. {
  59. var viewModel = _router.InstantiateViewModel<T>(configure);
  60. return await Popup(viewModel, canTapAway);
  61. }
  62. public static async Task<object?> Popup<T>(T viewModel, bool canTapAway = true)
  63. where T : IViewModelBase, IPopupViewModel
  64. {
  65. if (viewModel is IDualFunctionViewModel dualFunction)
  66. {
  67. dualFunction.IsPopup = true;
  68. }
  69. await viewModel.Activate();
  70. var _result = await DialogHostAvalonia.DialogHost.Show(viewModel, (object sender, DialogClosingEventArgs eventArgs) =>
  71. {
  72. if(!canTapAway && !viewModel.IsClosed)
  73. {
  74. eventArgs.Cancel();
  75. }
  76. });
  77. await viewModel.Deactivate();
  78. return _result;
  79. }
  80. public static async Task<TResult?> Popup<T, TResult>(Action<T>? configure = null, bool canTapAway = true)
  81. where T : IViewModelBase, IPopupViewModel<TResult>
  82. {
  83. var viewModel = _router.InstantiateViewModel<T>(configure);
  84. return await Popup<T, TResult>(viewModel, canTapAway);
  85. }
  86. public static async Task<TResult?> Popup<T, TResult>(T viewModel, bool canTapAway = true)
  87. where T : IViewModelBase, IPopupViewModel<TResult>
  88. {
  89. if (viewModel is IDualFunctionViewModel dualFunction)
  90. {
  91. dualFunction.IsPopup = true;
  92. }
  93. await viewModel.Activate();
  94. var _result = await DialogHostAvalonia.DialogHost.Show(viewModel, (object sender, DialogClosingEventArgs eventArgs) =>
  95. {
  96. if(!canTapAway && !viewModel.IsClosed)
  97. {
  98. eventArgs.Cancel();
  99. }
  100. });
  101. await viewModel.Deactivate();
  102. return viewModel.GetResult();
  103. }
  104. public static void Reset<T>(Action<T>? configure = null) where T : IViewModelBase
  105. {
  106. _router.Reset<T>(configure);
  107. }
  108. public static event Action<IViewModelBase, RouterDirection>? CurrentViewModelChanging;
  109. public static event Action<IViewModelBase>? CurrentViewModelChanged;
  110. }
  111. public class BasePopupViewModel<TResult> : ObservableObject, IPopupViewModel<TResult?>, IViewModelBase
  112. {
  113. #region IPopupViewModel
  114. public bool IsClosed { get; private set; }
  115. protected TResult? _result;
  116. public TResult? GetResult()
  117. {
  118. return _result;
  119. }
  120. public void Close(TResult? result)
  121. {
  122. _result = result;
  123. IsClosed = true;
  124. DialogHost.GetDialogSession(null)?.Close();
  125. }
  126. #endregion
  127. #region IViewModel
  128. public bool BackButtonVisible { get; set; }
  129. public bool ProgressVisible { get; set; }
  130. public AvaloniaMenuItemCollection PrimaryMenu { get; set; } = new();
  131. public AvaloniaMenuItemCollection SecondaryMenu { get; set; } = new();
  132. public Task Activate()
  133. {
  134. return Task.CompletedTask;
  135. }
  136. public Task Deactivate()
  137. {
  138. return Task.CompletedTask;
  139. }
  140. public virtual bool OnBackButtonPressed()
  141. {
  142. return true;
  143. }
  144. #endregion
  145. }