@@ -25,9 +25,26 @@ public static class MauiAppBuilderExtensionMethods
2525 /// The list of assemblies to scan for IViewModelBase, ContentPageBase, and DialogPageBase types.
2626 /// </param>
2727 /// <returns>The same builder that was sent in for chaining.</returns>
28+ public static MauiAppBuilder UseShieldMVVM (
29+ this MauiAppBuilder builder ,
30+ Func < Type , dynamic ? > typeResolverCallback ,
31+ params Assembly [ ] assembliesToScan ) => UseShieldMVVM ( builder , typeResolverCallback , null , assembliesToScan ) ;
32+
33+ /// <summary>
34+ /// Configures the built in INavigationService to navigate between pages via a ViewModel and
35+ /// registers all ViewModels, ContentPageBase, and DialogPageBase types.
36+ /// </summary>
37+ /// <param name="builder">A builder for .NET MAUI cross-platform applications and services.</param>
38+ /// <param name="typeResolverCallback">The callback to an IoC container to return the resolved type.</param>
39+ /// <param name="typesToMakeSingleton">An optional list of types to be added as Singleton instead of Transient.</param>
40+ /// <param name="assembliesToScan">
41+ /// The list of assemblies to scan for IViewModelBase, ContentPageBase, and DialogPageBase types.
42+ /// </param>
43+ /// <returns>The same builder that was sent in for chaining.</returns>
2844 public static MauiAppBuilder UseShieldMVVM (
2945 this MauiAppBuilder builder ,
3046 Func < Type , dynamic ? > typeResolverCallback ,
47+ HashSet < Type > ? typesToMakeSingleton ,
3148 params Assembly [ ] assembliesToScan )
3249 {
3350 builder . Services . AddSingleton < INavigationService > ( new NavigationService ( typeResolverCallback ) ) ;
@@ -41,9 +58,9 @@ public static MauiAppBuilder UseShieldMVVM(
4158 assembliesToScan = [ .. assemblies ] ;
4259 }
4360
44- ConfigureViewModels ( builder , assembliesToScan ) ;
45- ConfigurePages ( builder , assembliesToScan ) ;
46- ConfigureDialogs ( builder , assembliesToScan ) ;
61+ ConfigureViewModels ( builder , typesToMakeSingleton , assembliesToScan ) ;
62+ ConfigurePages ( builder , typesToMakeSingleton , assembliesToScan ) ;
63+ ConfigureDialogs ( builder , typesToMakeSingleton , assembliesToScan ) ;
4764
4865 return builder ;
4966 }
@@ -59,11 +76,26 @@ public static MauiAppBuilder UseShieldMVVM(
5976 /// <returns>The same builder that was sent in for chaining.</returns>
6077 public static MauiAppBuilder UseShieldMVVMNoNavigation (
6178 this MauiAppBuilder builder ,
79+ params Assembly [ ] assembliesToScan ) => UseShieldMVVMNoNavigation ( builder , null , assembliesToScan ) ;
80+
81+ /// <summary>
82+ /// Does NOT configure the built in INavigationService to navigate between pages. Only registers
83+ /// ViewModels, ContentPageBase, and DialogPageBase types.
84+ /// </summary>
85+ /// <param name="builder">A builder for .NET MAUI cross-platform applications and services.</param>
86+ /// <param name="typesToMakeSingleton">An optional list of types to be added as Singleton instead of Transient.</param>
87+ /// <param name="assembliesToScan">
88+ /// The list of assemblies to scan for IViewModelBase, ContentPageBase, and DialogPageBase types.
89+ /// </param>
90+ /// <returns>The same builder that was sent in for chaining.</returns>
91+ public static MauiAppBuilder UseShieldMVVMNoNavigation (
92+ this MauiAppBuilder builder ,
93+ HashSet < Type > ? typesToMakeSingleton ,
6294 params Assembly [ ] assembliesToScan )
6395 {
64- ConfigureViewModels ( builder , assembliesToScan ) ;
65- ConfigurePages ( builder , assembliesToScan ) ;
66- ConfigureDialogs ( builder , assembliesToScan ) ;
96+ ConfigureViewModels ( builder , typesToMakeSingleton , assembliesToScan ) ;
97+ ConfigurePages ( builder , typesToMakeSingleton , assembliesToScan ) ;
98+ ConfigureDialogs ( builder , typesToMakeSingleton , assembliesToScan ) ;
6799
68100 return builder ;
69101 }
@@ -73,16 +105,17 @@ public static MauiAppBuilder UseShieldMVVMNoNavigation(
73105 /// the Services IoC container.
74106 /// </summary>
75107 /// <param name="builder">A builder for .NET MAUI cross-platform applications and services.</param>
108+ /// <param name="typesToMakeSingleton">An optional list of types to be added as Singleton instead of Transient.</param>
76109 /// <param name="assembliesToScan">The list of assemblies to scan for IViewModelBase types.</param>
77110 /// <returns>The same builder that was sent in for chaining.</returns>
78- private static MauiAppBuilder ConfigureViewModels ( MauiAppBuilder builder , params Assembly [ ] assembliesToScan )
111+ private static MauiAppBuilder ConfigureViewModels ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , params Assembly [ ] assembliesToScan )
79112 {
80113 if ( assembliesToScan == null )
81114 return builder ;
82115
83116 foreach ( var assembly in assembliesToScan )
84117 {
85- RegisterViewModelsInAssembly ( builder , assembly ) ;
118+ RegisterViewModelsInAssembly ( builder , typesToMakeSingleton , assembly ) ;
86119 }
87120
88121 return builder ;
@@ -93,16 +126,17 @@ private static MauiAppBuilder ConfigureViewModels(MauiAppBuilder builder, params
93126 /// and registers them with the Services IoC container.
94127 /// </summary>
95128 /// <param name="builder">A builder for .NET MAUI cross-platform applications and services.</param>
129+ /// <param name="typesToMakeSingleton">An optional list of types to be added as Singleton instead of Transient.</param>
96130 /// <param name="assembliesToScan">The list of assemblies to scan for ContentPageBase<> types.</param>
97131 /// <returns>The same builder that was sent in for chaining.</returns>
98- private static MauiAppBuilder ConfigurePages ( MauiAppBuilder builder , params Assembly [ ] assembliesToScan )
132+ private static MauiAppBuilder ConfigurePages ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , params Assembly [ ] assembliesToScan )
99133 {
100134 if ( assembliesToScan == null )
101135 return builder ;
102136
103137 foreach ( var assembly in assembliesToScan )
104138 {
105- RegisterPagesInAssembly ( builder , assembly ) ;
139+ RegisterPagesInAssembly ( builder , typesToMakeSingleton , assembly ) ;
106140 }
107141
108142 return builder ;
@@ -113,33 +147,37 @@ private static MauiAppBuilder ConfigurePages(MauiAppBuilder builder, params Asse
113147 /// and registers them with the Services IoC container.
114148 /// </summary>
115149 /// <param name="builder">A builder for .NET MAUI cross-platform applications and services.</param>
150+ /// <param name="typesToMakeSingleton">An optional list of types to be added as Singleton instead of Transient.</param>
116151 /// <param name="assembliesToScan">The list of assemblies to scan for ContentPageBase<> types.</param>
117152 /// <returns>The same builder that was sent in for chaining.</returns>
118- private static MauiAppBuilder ConfigureDialogs ( MauiAppBuilder builder , params Assembly [ ] assembliesToScan )
153+ private static MauiAppBuilder ConfigureDialogs ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , params Assembly [ ] assembliesToScan )
119154 {
120155 if ( assembliesToScan == null )
121156 return builder ;
122157
123158 foreach ( var assembly in assembliesToScan )
124159 {
125- RegisterDialogsInAssembly ( builder , assembly ) ;
160+ RegisterDialogsInAssembly ( builder , typesToMakeSingleton , assembly ) ;
126161 }
127162
128163 return builder ;
129164 }
130165
131- private static void RegisterViewModelsInAssembly ( MauiAppBuilder builder , Assembly assembly )
166+ private static void RegisterViewModelsInAssembly ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , Assembly assembly )
132167 {
133168 foreach ( var type in assembly . GetTypes ( ) )
134169 {
135170 if ( type . IsAbstract || type . IsInterface || ! type . IsAssignableTo ( _vmType ) )
136171 continue ;
137172
138- builder . Services . AddTransient ( type ) ;
173+ if ( typesToMakeSingleton ? . Contains ( type ) == true )
174+ builder . Services . AddSingleton ( type ) ;
175+ else
176+ builder . Services . AddTransient ( type ) ;
139177 }
140178 }
141179
142- private static void RegisterPagesInAssembly ( MauiAppBuilder builder , Assembly assembly )
180+ private static void RegisterPagesInAssembly ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , Assembly assembly )
143181 {
144182 var types = assembly . GetTypes ( ) ;
145183 foreach ( var pageType in types )
@@ -150,13 +188,19 @@ private static void RegisterPagesInAssembly(MauiAppBuilder builder, Assembly ass
150188 var vmType = GetPageGenericType ( pageType ) ;
151189
152190 NavigationService . ViewModelPageLookup . TryAdd ( vmType , pageType ) ;
153- builder . Services . AddTransient ( _pageType . MakeGenericType ( vmType ) , pageType ) ;
154191
155- RegisterParentTypes ( builder , NavigationService . ViewModelPageLookup , _pageType , types , pageType , vmType ) ;
192+ Type genericType = _pageType . MakeGenericType ( vmType ) ;
193+
194+ if ( typesToMakeSingleton ? . Contains ( genericType ) == true )
195+ builder . Services . AddSingleton ( genericType , pageType ) ;
196+ else
197+ builder . Services . AddTransient ( genericType , pageType ) ;
198+
199+ RegisterParentTypes ( builder , NavigationService . ViewModelPageLookup , _pageType , types , pageType , vmType , typesToMakeSingleton ) ;
156200 }
157201 }
158202
159- private static void RegisterDialogsInAssembly ( MauiAppBuilder builder , Assembly assembly )
203+ private static void RegisterDialogsInAssembly ( MauiAppBuilder builder , HashSet < Type > ? typesToMakeSingleton , Assembly assembly )
160204 {
161205 var types = assembly . GetTypes ( ) ;
162206 foreach ( var pageType in types )
@@ -167,9 +211,15 @@ private static void RegisterDialogsInAssembly(MauiAppBuilder builder, Assembly a
167211 var vmType = GetPageGenericType ( pageType ) ;
168212
169213 NavigationService . ViewModelDialogPageLookup . TryAdd ( vmType , pageType ) ;
170- builder . Services . AddTransient ( _dialogPageType . MakeGenericType ( vmType ) , pageType ) ;
171214
172- RegisterParentTypes ( builder , NavigationService . ViewModelDialogPageLookup , _dialogPageType , types , pageType , vmType ) ;
215+ Type genericType = _dialogPageType . MakeGenericType ( vmType ) ;
216+
217+ if ( typesToMakeSingleton ? . Contains ( genericType ) == true )
218+ builder . Services . AddSingleton ( genericType , pageType ) ;
219+ else
220+ builder . Services . AddTransient ( _dialogPageType . MakeGenericType ( vmType ) , pageType ) ;
221+
222+ RegisterParentTypes ( builder , NavigationService . ViewModelDialogPageLookup , _dialogPageType , types , pageType , vmType , typesToMakeSingleton ) ;
173223 }
174224 }
175225
@@ -179,17 +229,24 @@ private static void RegisterParentTypes(
179229 Type genericType ,
180230 Type [ ] types ,
181231 Type pageType ,
182- Type baseViewModelType )
232+ Type baseViewModelType ,
233+ HashSet < Type > ? typesToMakeSingleton )
183234 {
184235 foreach ( var vmType in types )
185236 {
186237 if ( vmType . IsAbstract || vmType . IsInterface || vmType . BaseType != baseViewModelType )
187238 continue ;
188239
189240 lookup . TryAdd ( vmType , pageType ) ;
190- builder . Services . AddTransient ( genericType . MakeGenericType ( vmType ) , pageType ) ;
191241
192- RegisterParentTypes ( builder , lookup , genericType , types , pageType , vmType ) ;
242+ Type subGenericType = genericType . MakeGenericType ( vmType ) ;
243+
244+ if ( typesToMakeSingleton ? . Contains ( subGenericType ) == true )
245+ builder . Services . AddSingleton ( subGenericType , pageType ) ;
246+ else
247+ builder . Services . AddTransient ( subGenericType , pageType ) ;
248+
249+ RegisterParentTypes ( builder , lookup , genericType , types , pageType , vmType , typesToMakeSingleton ) ;
193250 }
194251 }
195252
0 commit comments