11using System ;
2+ using System . Collections . Generic ;
23using System . Diagnostics ;
34using System . Threading . Tasks ;
45using Avalonia ;
56using Avalonia . Controls ;
7+ using Avalonia . Interactivity ;
68
79namespace Caliburn . Micro
810{
@@ -15,18 +17,24 @@ public class NavigationFrame : ContentControl, INavigationService
1517 private static readonly ILog Log = LogManager . GetLog ( typeof ( NavigationFrame ) ) ;
1618
1719 private string defaultContent { get ; } = "Default Content" ;
18-
20+ private readonly List < object > navigationStack = new List < object > ( ) ;
21+ private int navigationStackIndex = 0 ;
1922 /// <summary>
2023 /// Initializes a new instance of the <see cref="NavigationFrame"/> class.
2124 /// </summary>
2225 public NavigationFrame ( )
2326 {
2427 Content = defaultContent ;
25- this . AttachedToVisualTree += NavigationFrame_AttachedToVisualTree ;
26- LayoutUpdated += NavigationFrame_LayoutUpdated ;
28+ this . Loaded += NavigationFrame_Loaded ;
2729 ContentProperty . Changed . AddClassHandler < NavigationFrame > ( ( sender , e ) => NavigationFrame_ContentChanged ( sender , e ) ) ;
2830 }
2931
32+ private void NavigationFrame_Loaded ( object sender , RoutedEventArgs e )
33+ {
34+ Log . Info ( "Navigation Frame loaded" ) ;
35+ OnNavigationServiceReady ( new EventArgs ( ) ) ;
36+ }
37+
3038 private void NavigationFrame_ContentChanged ( NavigationFrame sender , AvaloniaPropertyChangedEventArgs e )
3139 {
3240 Log . Info ( "Content changed" ) ;
@@ -66,15 +74,6 @@ private async void NavigationFrame_TransitionCompleted(object sender, Transition
6674 }
6775 }
6876
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-
7877 /// <summary>
7978 /// Occurs when the navigation service is ready.
8079 /// </summary>
@@ -98,7 +97,7 @@ protected virtual void OnNavigationServiceReady(EventArgs e)
9897 /// Navigates to the specified view model.
9998 /// </summary>
10099 /// <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 )
102101 {
103102 if ( viewModel == null )
104103 {
@@ -117,17 +116,25 @@ private void NavigateToViewModel(object viewModel)
117116
118117 ViewModelBinder . Bind ( viewModel , viewInstance , null ) ;
119118 Log . Info ( $ "View Model { viewModel } ") ;
120- Log . Info ( $ "View { viewInstance } ") ;
121119 Tag = "Navigating" ;
122120 viewInstance . DataContext = viewModel ;
123121 Content = viewInstance ;
124-
122+ if ( addToStack )
123+ {
124+ navigationStack . Add ( viewModel ) ;
125+ navigationStackIndex = navigationStack . Count - 1 ;
126+ }
125127 }
126128
127129 /// <inheritdoc/>
128130 public Task GoBackAsync ( bool animated = true )
129131 {
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 ;
131138 }
132139
133140 /// <inheritdoc/>
@@ -145,18 +152,27 @@ public Task NavigateToViewAsync<T>(object parameter = null, bool animated = true
145152 /// <inheritdoc/>
146153 public Task NavigateToViewModelAsync ( Type viewModelType , object parameter = null , bool animated = true )
147154 {
148- Log . Info ( $ "View model type { viewModelType } ") ;
149155 var vm = Caliburn . Micro . IoC . GetInstance ( viewModelType , null ) ;
150- Log . Info ( $ "VM is null { vm == null } " ) ;
156+ TryInjectParameters ( vm , parameter ) ;
151157 NavigateToViewModel ( vm ) ;
152158
153159 return Task . CompletedTask ;
154160 }
155161
162+ /// <summary>
163+ /// Gets or sets the ViewModel.
164+ /// </summary>
165+ public static string ViewModel
166+ {
167+ get ; set ;
168+ }
169+
156170 /// <inheritdoc/>
157171 public Task NavigateToViewModelAsync < T > ( object parameter = null , bool animated = true )
158172 {
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 ) ;
160176 }
161177
162178 /// <inheritdoc/>
@@ -170,6 +186,7 @@ public Task NavigateToViewModelAsync(Screen viewModel, object parameter = null,
170186 /// <inheritdoc/>
171187 public Task GoBackToRootAsync ( bool animated = true )
172188 {
189+ Log . Info ( "Going back to root" ) ;
173190 throw new NotImplementedException ( ) ;
174191 }
175192
@@ -181,5 +198,41 @@ private string GetDebuggerDisplay()
181198 {
182199 return $ "{ nameof ( NavigationFrame ) } : Content={ Content } , IsNavigationServiceReady={ NavigationServiceReady != null } ";
183200 }
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+ }
184237 }
185238}
0 commit comments