1
1
using Microsoft . Extensions . DependencyInjection ;
2
2
using PCL . Neo . ViewModels ;
3
3
using System ;
4
+ using System . Collections . Generic ;
4
5
using System . Reflection ;
5
6
6
7
namespace PCL . Neo . Services ;
7
8
9
+ public enum NavigationType
10
+ {
11
+ Forward ,
12
+ Backward
13
+ }
14
+
15
+ public class NavigationEventArgs : EventArgs
16
+ {
17
+ public ViewModelBase ? OldViewModel { get ; }
18
+ public ViewModelBase ? NewViewModel { get ; }
19
+ public NavigationType NavigationType { get ; }
20
+
21
+ public NavigationEventArgs ( ViewModelBase ? oldViewModel , ViewModelBase ? newViewModel , NavigationType navigationType )
22
+ {
23
+ OldViewModel = oldViewModel ;
24
+ NewViewModel = newViewModel ;
25
+ NavigationType = navigationType ;
26
+ }
27
+ }
28
+
8
29
public class NavigationService
9
30
{
10
31
public IServiceProvider ServiceProvider { get ; init ; }
11
32
12
33
public event Action < ViewModelBase ? > ? CurrentViewModelChanged ;
13
34
public event Action < ViewModelBase ? > ? CurrentSubViewModelChanged ;
35
+ public event Action < NavigationEventArgs > ? Navigating ;
36
+
37
+ // 导航历史记录
38
+ private readonly Stack < ( Type ViewModelType , Type ? SubViewModelType ) > _navigationHistory = new ( ) ;
39
+ // 最大历史记录数量
40
+ private const int MaxHistoryCount = 30 ;
14
41
15
42
private ViewModelBase ? _currentViewModel ;
16
43
public ViewModelBase ? CurrentViewModel
@@ -20,6 +47,8 @@ protected set
20
47
{
21
48
if ( value == _currentViewModel )
22
49
return ;
50
+
51
+ var oldViewModel = _currentViewModel ;
23
52
_currentViewModel = value ;
24
53
CurrentViewModelChanged ? . Invoke ( value ) ;
25
54
}
@@ -33,18 +62,52 @@ protected set
33
62
{
34
63
if ( value == _currentSubViewModel )
35
64
return ;
65
+
66
+ var oldSubViewModel = _currentSubViewModel ;
36
67
_currentSubViewModel = value ;
37
68
CurrentSubViewModelChanged ? . Invoke ( value ) ;
38
69
}
39
70
}
40
71
72
+ public bool CanGoBack => _navigationHistory . Count > 0 ;
73
+
41
74
public NavigationService ( IServiceProvider serviceProvider )
42
75
{
43
76
ServiceProvider = serviceProvider ;
44
77
}
45
78
46
79
public virtual T Goto < T > ( ) where T : ViewModelBase
47
80
{
81
+ var oldViewModel = CurrentViewModel ;
82
+ var oldSubViewModel = CurrentSubViewModel ;
83
+
84
+ // 保存当前状态到历史记录
85
+ if ( CurrentViewModel != null )
86
+ {
87
+ _navigationHistory . Push ( ( CurrentViewModel . GetType ( ) , CurrentSubViewModel ? . GetType ( ) ) ) ;
88
+
89
+ // 限制历史记录数量
90
+ if ( _navigationHistory . Count > MaxHistoryCount )
91
+ {
92
+ var tempStack = new Stack < ( Type , Type ? ) > ( ) ;
93
+ var count = 0 ;
94
+
95
+ while ( _navigationHistory . Count > 0 && count < MaxHistoryCount )
96
+ {
97
+ tempStack . Push ( _navigationHistory . Pop ( ) ) ;
98
+ count ++ ;
99
+ }
100
+
101
+ _navigationHistory . Clear ( ) ;
102
+ while ( tempStack . Count > 0 )
103
+ {
104
+ _navigationHistory . Push ( tempStack . Pop ( ) ) ;
105
+ }
106
+ }
107
+ }
108
+
109
+ T targetVm ;
110
+
48
111
if ( typeof ( T ) . GetCustomAttribute < DefaultSubViewModelAttribute > ( ) is { } dsvm )
49
112
{
50
113
var vm = CurrentViewModel as T ;
@@ -55,10 +118,9 @@ public virtual T Goto<T>() where T : ViewModelBase
55
118
}
56
119
if ( CurrentSubViewModel ? . GetType ( ) != dsvm . SubViewModel )
57
120
CurrentSubViewModel = ServiceProvider . GetRequiredService ( dsvm . SubViewModel ) as ViewModelBase ;
58
- return vm ;
121
+ targetVm = vm ;
59
122
}
60
-
61
- if ( typeof ( T ) . GetCustomAttribute < SubViewModelOfAttribute > ( ) is { } svmo )
123
+ else if ( typeof ( T ) . GetCustomAttribute < SubViewModelOfAttribute > ( ) is { } svmo )
62
124
{
63
125
var subVm = CurrentSubViewModel as T ;
64
126
if ( CurrentViewModel ? . GetType ( ) != svmo . ParentViewModel )
@@ -68,16 +130,66 @@ public virtual T Goto<T>() where T : ViewModelBase
68
130
subVm = ServiceProvider . GetRequiredService < T > ( ) ;
69
131
CurrentSubViewModel = subVm ;
70
132
}
71
- return subVm ;
133
+ targetVm = subVm ;
72
134
}
73
-
74
- var targetVm = CurrentViewModel ? . GetType ( ) != typeof ( T ) || CurrentSubViewModel ? . GetType ( ) != typeof ( T )
75
- ? ServiceProvider . GetRequiredService < T > ( )
76
- : ( T ) CurrentViewModel ;
77
- if ( CurrentViewModel ? . GetType ( ) != typeof ( T ) )
78
- CurrentViewModel = targetVm ;
79
- if ( CurrentSubViewModel ? . GetType ( ) != typeof ( T ) )
80
- CurrentSubViewModel = targetVm ;
135
+ else
136
+ {
137
+ targetVm = CurrentViewModel ? . GetType ( ) != typeof ( T ) || CurrentSubViewModel ? . GetType ( ) != typeof ( T )
138
+ ? ServiceProvider . GetRequiredService < T > ( )
139
+ : ( T ) CurrentViewModel ;
140
+ if ( CurrentViewModel ? . GetType ( ) != typeof ( T ) )
141
+ CurrentViewModel = targetVm ;
142
+ if ( CurrentSubViewModel ? . GetType ( ) != typeof ( T ) )
143
+ CurrentSubViewModel = targetVm ;
144
+ }
145
+
146
+ // 触发导航事件
147
+ Navigating ? . Invoke ( new NavigationEventArgs ( oldViewModel , CurrentViewModel , NavigationType . Forward ) ) ;
148
+
81
149
return targetVm ;
82
150
}
151
+
152
+ /// <summary>
153
+ /// 返回上一个导航状态
154
+ /// </summary>
155
+ /// <returns>是否成功返回</returns>
156
+ public bool GoBack ( )
157
+ {
158
+ if ( ! CanGoBack )
159
+ return false ;
160
+
161
+ var oldViewModel = CurrentViewModel ;
162
+ var oldSubViewModel = CurrentSubViewModel ;
163
+
164
+ var ( viewModelType , subViewModelType ) = _navigationHistory . Pop ( ) ;
165
+
166
+ // 恢复主视图
167
+ if ( viewModelType != null )
168
+ {
169
+ CurrentViewModel = ServiceProvider . GetRequiredService ( viewModelType ) as ViewModelBase ;
170
+ }
171
+
172
+ // 恢复子视图
173
+ if ( subViewModelType != null )
174
+ {
175
+ CurrentSubViewModel = ServiceProvider . GetRequiredService ( subViewModelType ) as ViewModelBase ;
176
+ }
177
+ else
178
+ {
179
+ CurrentSubViewModel = null ;
180
+ }
181
+
182
+ // 触发导航事件
183
+ Navigating ? . Invoke ( new NavigationEventArgs ( oldViewModel , CurrentViewModel , NavigationType . Backward ) ) ;
184
+
185
+ return true ;
186
+ }
187
+
188
+ /// <summary>
189
+ /// 清空导航历史
190
+ /// </summary>
191
+ public void ClearHistory ( )
192
+ {
193
+ _navigationHistory . Clear ( ) ;
194
+ }
83
195
}
0 commit comments