1
1
using System ;
2
+ using System . Collections . Generic ;
2
3
using System . Diagnostics ;
3
4
using System . Threading . Tasks ;
4
5
using Avalonia ;
5
6
using Avalonia . Controls ;
7
+ using Avalonia . Interactivity ;
6
8
7
9
namespace Caliburn . Micro
8
10
{
@@ -15,18 +17,24 @@ public class NavigationFrame : ContentControl, INavigationService
15
17
private static readonly ILog Log = LogManager . GetLog ( typeof ( NavigationFrame ) ) ;
16
18
17
19
private string defaultContent { get ; } = "Default Content" ;
18
-
20
+ private readonly List < object > navigationStack = new List < object > ( ) ;
21
+ private int navigationStackIndex = 0 ;
19
22
/// <summary>
20
23
/// Initializes a new instance of the <see cref="NavigationFrame"/> class.
21
24
/// </summary>
22
25
public NavigationFrame ( )
23
26
{
24
27
Content = defaultContent ;
25
- this . AttachedToVisualTree += NavigationFrame_AttachedToVisualTree ;
26
- LayoutUpdated += NavigationFrame_LayoutUpdated ;
28
+ this . Loaded += NavigationFrame_Loaded ;
27
29
ContentProperty . Changed . AddClassHandler < NavigationFrame > ( ( sender , e ) => NavigationFrame_ContentChanged ( sender , e ) ) ;
28
30
}
29
31
32
+ private void NavigationFrame_Loaded ( object sender , RoutedEventArgs e )
33
+ {
34
+ Log . Info ( "Navigation Frame loaded" ) ;
35
+ OnNavigationServiceReady ( new EventArgs ( ) ) ;
36
+ }
37
+
30
38
private void NavigationFrame_ContentChanged ( NavigationFrame sender , AvaloniaPropertyChangedEventArgs e )
31
39
{
32
40
Log . Info ( "Content changed" ) ;
@@ -66,15 +74,6 @@ private async void NavigationFrame_TransitionCompleted(object sender, Transition
66
74
}
67
75
}
68
76
69
- /// <summary>
70
- /// Handles the event when the frame is attached to the visual tree.
71
- /// </summary>
72
- private void NavigationFrame_AttachedToVisualTree ( object sender , VisualTreeAttachmentEventArgs e )
73
- {
74
- Log . Info ( "Attached to visual tree" ) ;
75
- OnNavigationServiceReady ( new EventArgs ( ) ) ;
76
- }
77
-
78
77
/// <summary>
79
78
/// Occurs when the navigation service is ready.
80
79
/// </summary>
@@ -98,7 +97,7 @@ protected virtual void OnNavigationServiceReady(EventArgs e)
98
97
/// Navigates to the specified view model.
99
98
/// </summary>
100
99
/// <param name="viewModel">The view model to navigate to.</param>
101
- private void NavigateToViewModel ( object viewModel )
100
+ private void NavigateToViewModel ( object viewModel , bool addToStack = true )
102
101
{
103
102
if ( viewModel == null )
104
103
{
@@ -117,17 +116,25 @@ private void NavigateToViewModel(object viewModel)
117
116
118
117
ViewModelBinder . Bind ( viewModel , viewInstance , null ) ;
119
118
Log . Info ( $ "View Model { viewModel } ") ;
120
- Log . Info ( $ "View { viewInstance } ") ;
121
119
Tag = "Navigating" ;
122
120
viewInstance . DataContext = viewModel ;
123
121
Content = viewInstance ;
124
-
122
+ if ( addToStack )
123
+ {
124
+ navigationStack . Add ( viewModel ) ;
125
+ navigationStackIndex = navigationStack . Count - 1 ;
126
+ }
125
127
}
126
128
127
129
/// <inheritdoc/>
128
130
public Task GoBackAsync ( bool animated = true )
129
131
{
130
- throw new NotImplementedException ( ) ;
132
+ Log . Info ( "Going back" ) ;
133
+ if ( navigationStackIndex > 0 )
134
+ navigationStackIndex -- ;
135
+
136
+ NavigateToViewModel ( navigationStack [ navigationStackIndex ] , false ) ;
137
+ return Task . CompletedTask ;
131
138
}
132
139
133
140
/// <inheritdoc/>
@@ -145,18 +152,27 @@ public Task NavigateToViewAsync<T>(object parameter = null, bool animated = true
145
152
/// <inheritdoc/>
146
153
public Task NavigateToViewModelAsync ( Type viewModelType , object parameter = null , bool animated = true )
147
154
{
148
- Log . Info ( $ "View model type { viewModelType } ") ;
149
155
var vm = Caliburn . Micro . IoC . GetInstance ( viewModelType , null ) ;
150
- Log . Info ( $ "VM is null { vm == null } " ) ;
156
+ TryInjectParameters ( vm , parameter ) ;
151
157
NavigateToViewModel ( vm ) ;
152
158
153
159
return Task . CompletedTask ;
154
160
}
155
161
162
+ /// <summary>
163
+ /// Gets or sets the ViewModel.
164
+ /// </summary>
165
+ public static string ViewModel
166
+ {
167
+ get ; set ;
168
+ }
169
+
156
170
/// <inheritdoc/>
157
171
public Task NavigateToViewModelAsync < T > ( object parameter = null , bool animated = true )
158
172
{
159
- throw new NotImplementedException ( ) ;
173
+ Log . Info ( $ "Navigate to View model type { typeof ( T ) } ") ;
174
+ Log . Info ( $ "Navigate to View model parameter not null { parameter != null } ") ;
175
+ return NavigateToViewModelAsync ( typeof ( T ) , parameter , animated ) ;
160
176
}
161
177
162
178
/// <inheritdoc/>
@@ -170,6 +186,7 @@ public Task NavigateToViewModelAsync(Screen viewModel, object parameter = null,
170
186
/// <inheritdoc/>
171
187
public Task GoBackToRootAsync ( bool animated = true )
172
188
{
189
+ Log . Info ( "Going back to root" ) ;
173
190
throw new NotImplementedException ( ) ;
174
191
}
175
192
@@ -181,5 +198,41 @@ private string GetDebuggerDisplay()
181
198
{
182
199
return $ "{ nameof ( NavigationFrame ) } : Content={ Content } , IsNavigationServiceReady={ NavigationServiceReady != null } ";
183
200
}
201
+
202
+ /// <summary>
203
+ /// Attempts to inject query string parameters from the view into the view model.
204
+ /// </summary>
205
+ /// <param name="viewModel"> The view model.</param>
206
+ /// <param name="parameter"> The parameter.</param>
207
+ protected virtual void TryInjectParameters ( object viewModel , object parameter )
208
+ {
209
+ var viewModelType = viewModel . GetType ( ) ;
210
+
211
+ var dictionaryParameter = parameter as IDictionary < string , object > ;
212
+
213
+ if ( dictionaryParameter != null )
214
+ {
215
+ foreach ( var pair in dictionaryParameter )
216
+ {
217
+ var property = viewModelType . GetPropertyCaseInsensitive ( pair . Key ) ;
218
+
219
+ if ( property == null )
220
+ {
221
+ continue ;
222
+ }
223
+
224
+ property . SetValue ( viewModel , MessageBinder . CoerceValue ( property . PropertyType , pair . Value , null ) , null ) ;
225
+ }
226
+ }
227
+ else
228
+ {
229
+ var property = viewModelType . GetPropertyCaseInsensitive ( "Parameter" ) ;
230
+
231
+ if ( property == null )
232
+ return ;
233
+
234
+ property . SetValue ( viewModel , MessageBinder . CoerceValue ( property . PropertyType , parameter , null ) , null ) ;
235
+ }
236
+ }
184
237
}
185
238
}
0 commit comments