9
9
10
10
namespace UnityWeld . Binding . Internal
11
11
{
12
+ /// <summary>
13
+ /// ViewModel provider delegate
14
+ /// </summary>
15
+ /// <param name="component"></param>
16
+ /// <returns>Tuple with ViewModel name and ViewModel itself</returns>
17
+ public delegate ViewModelProviderData ViewModelProviderDelegate ( Component component ) ;
18
+
19
+ /// <summary>
20
+ /// Contains ViewModel data
21
+ /// </summary>
22
+ public class ViewModelProviderData
23
+ {
24
+ public readonly object Model ;
25
+ public readonly string TypeName ;
26
+
27
+ public ViewModelProviderData ( object model , string typeName )
28
+ {
29
+ Model = model ;
30
+ TypeName = typeName ;
31
+ }
32
+ }
33
+
12
34
/// <summary>
13
35
/// Helper class for setting up the factory for use in the editor.
14
36
/// </summary>
15
37
public static class TypeResolver
16
38
{
39
+ private static readonly IList < Type > BindingAttributeTypes = new List < Type > ( 2 )
40
+ {
41
+ typeof ( BindingAttribute ) //this should be the only ref to default binding attribute
42
+ } ;
43
+
44
+ private static readonly IList < ViewModelProviderDelegate > ViewModelProviders = new List < ViewModelProviderDelegate > ( 2 )
45
+ {
46
+ DefaultViewModelProvider
47
+ } ;
48
+
17
49
private static Type [ ] typesWithBindingAttribute ;
18
50
19
51
/// <summary>
@@ -28,7 +60,7 @@ public static IEnumerable<Type> TypesWithBindingAttribute
28
60
{
29
61
if ( typesWithBindingAttribute == null )
30
62
{
31
- typesWithBindingAttribute = FindTypesMarkedByAttribute ( typeof ( BindingAttribute ) ) ;
63
+ typesWithBindingAttribute = FindTypesMarkedByBindingAttribute ( ) ;
32
64
}
33
65
34
66
return typesWithBindingAttribute ;
@@ -58,6 +90,20 @@ public static IEnumerable<Type> TypesWithAdapterAttribute
58
90
59
91
private static Type [ ] typesWithWeldContainerAttribute ;
60
92
93
+ /// <summary>
94
+ /// Impliments default view model provider
95
+ /// </summary>
96
+ private static ViewModelProviderData DefaultViewModelProvider ( Component component )
97
+ {
98
+ var provider = component as IViewModelProvider ;
99
+ if ( provider == null )
100
+ {
101
+ return null ;
102
+ }
103
+
104
+ return new ViewModelProviderData ( provider . GetViewModel ( ) , provider . GetViewModelTypeName ( ) ) ;
105
+ }
106
+
61
107
/// <summary>
62
108
/// Find all types with WeldContainerAttribute. This works in the same way as
63
109
/// TypesWithAdapterAttribute and TypesWithBindingAttribute in that it finds it
@@ -101,6 +147,21 @@ private static Type[] FindTypesMarkedByAttribute(Type attributeType)
101
147
return typesFound . ToArray ( ) ;
102
148
}
103
149
150
+ /// <summary>
151
+ /// Find all types marked with binding attribute
152
+ /// </summary>
153
+ /// <returns></returns>
154
+ private static Type [ ] FindTypesMarkedByBindingAttribute ( )
155
+ {
156
+ var result = new List < Type > ( ) ;
157
+ foreach ( var attributeType in BindingAttributeTypes )
158
+ {
159
+ result . AddRange ( FindTypesMarkedByAttribute ( attributeType ) ) ;
160
+ }
161
+
162
+ return result . ToArray ( ) ;
163
+ }
164
+
104
165
/// <summary>
105
166
/// Returns an enumerable of all known types.
106
167
/// </summary>
@@ -205,21 +266,18 @@ private static IEnumerable<Type> FindAvailableViewModelTypes(AbstractMemberBindi
205
266
}
206
267
207
268
// Case where a ViewModelBinding is used to bind a non-MonoBehaviour class.
208
- var viewModelBinding = component as IViewModelProvider ;
209
- if ( viewModelBinding != null )
269
+ var viewModelData = component . GetViewModelData ( ) ;
270
+ if ( viewModelData != null )
210
271
{
211
- var viewModelTypeName = viewModelBinding . GetViewModelTypeName ( ) ;
212
272
// Ignore view model bindings that haven't been set up yet.
213
- if ( string . IsNullOrEmpty ( viewModelTypeName ) )
214
- {
273
+ if ( string . IsNullOrEmpty ( viewModelData . TypeName ) )
215
274
continue ;
216
- }
217
275
218
276
foundAtLeastOneBinding = true ;
219
277
220
- yield return GetViewModelType ( viewModelBinding . GetViewModelTypeName ( ) ) ;
278
+ yield return GetViewModelType ( viewModelData . TypeName ) ;
221
279
}
222
- else if ( component . GetType ( ) . GetCustomAttributes ( typeof ( BindingAttribute ) , false ) . Any ( ) )
280
+ else if ( component . GetType ( ) . HasBindingAttribute ( ) )
223
281
{
224
282
// Case where we are binding to an existing MonoBehaviour.
225
283
foundAtLeastOneBinding = true ;
@@ -246,9 +304,7 @@ public static BindableMember<PropertyInfo>[] FindBindableProperties(AbstractMemb
246
304
. SelectMany ( type => GetPublicProperties ( type )
247
305
. Select ( p => new BindableMember < PropertyInfo > ( p , type ) )
248
306
)
249
- . Where ( p => p . Member
250
- . GetCustomAttributes ( typeof ( BindingAttribute ) , false )
251
- . Any ( ) // Filter out properties that don't have [Binding].
307
+ . Where ( p => p . Member . HasBindingAttribute ( ) // Filter out properties that don't have [Binding].
252
308
)
253
309
. ToArray ( ) ;
254
310
}
@@ -295,7 +351,7 @@ public static BindableMember<MethodInfo>[] FindBindableMethods(EventBinding targ
295
351
. Select ( m => new BindableMember < MethodInfo > ( m , type ) )
296
352
)
297
353
. Where ( m => m . Member . GetParameters ( ) . Length == 0 )
298
- . Where ( m => m . Member . GetCustomAttributes ( typeof ( BindingAttribute ) , false ) . Any ( )
354
+ . Where ( m => m . Member . HasBindingAttribute ( )
299
355
&& ! m . MemberName . StartsWith ( "get_" ) ) // Exclude property getters, since we aren't doing anything with the return value of the bound method anyway.
300
356
. ToArray ( ) ;
301
357
}
@@ -310,5 +366,73 @@ public static BindableMember<PropertyInfo>[] FindBindableCollectionProperties(Co
310
366
. Where ( p => ! typeof ( string ) . IsAssignableFrom ( p . Member . PropertyType ) )
311
367
. ToArray ( ) ;
312
368
}
369
+
370
+ /// <summary>
371
+ /// Register custom binding attribute.
372
+ /// This will allow to mark bindable properties in external dlls without referencing UnityWeld.
373
+ /// </summary>
374
+ /// <typeparam name="T"></typeparam>
375
+ public static void RegisterCustomBindingAttribute < T > ( ) where T : Attribute
376
+ {
377
+ var type = typeof ( T ) ;
378
+ if ( BindingAttributeTypes . Contains ( type ) )
379
+ {
380
+ return ;
381
+ }
382
+
383
+ BindingAttributeTypes . Add ( type ) ;
384
+ }
385
+
386
+ /// <summary>
387
+ /// Register custom ViewModel provider.
388
+ /// This will allow to use custom ViewModel providers in external dlls without referencing UnityWeld.
389
+ /// </summary>
390
+ /// <param name="provider"></param>
391
+ public static void RegisterCustomViewModelProvider ( ViewModelProviderDelegate provider )
392
+ {
393
+ if ( ViewModelProviders . Contains ( provider ) )
394
+ {
395
+ return ;
396
+ }
397
+
398
+ ViewModelProviders . Add ( provider ) ;
399
+ }
400
+
401
+ /// <summary>
402
+ /// Check if type has binding attribute
403
+ /// </summary>
404
+ public static bool HasBindingAttribute ( this MemberInfo type )
405
+ {
406
+ //for to avoid GC
407
+ for ( var index = 0 ; index < BindingAttributeTypes . Count ; index ++ )
408
+ {
409
+ if ( type . GetCustomAttributes ( BindingAttributeTypes [ index ] , false ) . Any ( ) )
410
+ {
411
+ return true ;
412
+ }
413
+ }
414
+
415
+ return false ;
416
+ }
417
+
418
+ /// <summary>
419
+ /// Get ViewModel data from component
420
+ /// </summary>
421
+ public static ViewModelProviderData GetViewModelData ( this Component component )
422
+ {
423
+ if ( component == null )
424
+ return null ;
425
+
426
+ //for to avoid GC
427
+ for ( var i = 0 ; i < ViewModelProviders . Count ; i ++ )
428
+ {
429
+ var data = ViewModelProviders [ i ] ( component ) ;
430
+
431
+ if ( data != null )
432
+ return data ;
433
+ }
434
+
435
+ return null ;
436
+ }
313
437
}
314
438
}
0 commit comments