Navigation.cs 5.3 KB

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