@@ -674,6 +674,12 @@ private void BuildBackingFields(IIndentedStringBuilder writer)
674
674
}
675
675
}
676
676
677
+ foreach ( var xBindEventHandler in CurrentScope . xBindEventsHandlers )
678
+ {
679
+ // Create load-time subjects for ElementName references not in local scope
680
+ writer . AppendLineInvariant ( $ "{ FormatAccessibility ( xBindEventHandler . Accessibility ) } { GetGlobalizedTypeName ( xBindEventHandler . Type ) } { xBindEventHandler . Name } ;") ;
681
+ }
682
+
677
683
foreach ( var remainingReference in CurrentScope . ReferencedElementNames )
678
684
{
679
685
// Create load-time subjects for ElementName references not in local scope
@@ -795,16 +801,10 @@ private void BuildCompiledBindingsInitializer(IndentedStringBuilder writer, stri
795
801
writer . AppendLineInvariant ( "Bindings.Update();" ) ;
796
802
}
797
803
798
- for ( var i = 0 ; i < CurrentScope . Components . Count ; i ++ )
799
- {
800
- var component = CurrentScope . Components [ i ] ;
801
-
802
- if ( HasMarkupExtensionNeedingComponent ( component ) && IsDependencyObject ( component ) )
803
- {
804
- writer . AppendLineInvariant ( $ "_component_{ i } .UpdateResourceBindings();") ;
805
- }
806
- }
804
+ BuildComponentResouceBindingUpdates ( writer ) ;
805
+ BuildxBindEventHandlerInitializers ( writer ) ;
807
806
}
807
+
808
808
writer . AppendLineInvariant ( ";" ) ;
809
809
}
810
810
}
@@ -820,21 +820,38 @@ private void BuildCompiledBindingsInitializerForTemplate(IIndentedStringBuilder
820
820
{
821
821
using ( writer . BlockInvariant ( $ "__fe.Loading += delegate") )
822
822
{
823
- for ( var i = 0 ; i < CurrentScope . Components . Count ; i ++ )
824
- {
825
- var component = CurrentScope . Components [ i ] ;
826
-
827
- if ( HasMarkupExtensionNeedingComponent ( component ) && IsDependencyObject ( component ) )
828
- {
829
- writer . AppendLineInvariant ( $ "_component_{ i } .UpdateResourceBindings();") ;
830
- }
831
- }
823
+ BuildComponentResouceBindingUpdates ( writer ) ;
824
+ BuildxBindEventHandlerInitializers ( writer ) ;
832
825
}
833
826
writer . AppendLineInvariant ( ";" ) ;
834
827
}
835
828
}
836
829
}
837
830
831
+ private void BuildxBindEventHandlerInitializers ( IIndentedStringBuilder writer )
832
+ {
833
+ foreach ( var xBindEventHandler in CurrentScope . xBindEventsHandlers )
834
+ {
835
+ writer . AppendLineInvariant ( $ "{ xBindEventHandler . Name } ?.Invoke();") ;
836
+
837
+ // Only needs to happen once per visual tree creation
838
+ writer . AppendLineInvariant ( $ "{ xBindEventHandler . Name } = null;") ;
839
+ }
840
+ }
841
+
842
+ private void BuildComponentResouceBindingUpdates ( IIndentedStringBuilder writer )
843
+ {
844
+ for ( var i = 0 ; i < CurrentScope . Components . Count ; i ++ )
845
+ {
846
+ var component = CurrentScope . Components [ i ] ;
847
+
848
+ if ( HasMarkupExtensionNeedingComponent ( component ) && IsDependencyObject ( component ) )
849
+ {
850
+ writer . AppendLineInvariant ( $ "_component_{ i } .UpdateResourceBindings();") ;
851
+ }
852
+ }
853
+ }
854
+
838
855
private void BuildComponentFields ( IndentedStringBuilder writer )
839
856
{
840
857
for ( var i = 0 ; i < CurrentScope . Components . Count ; i ++ )
@@ -3069,8 +3086,40 @@ void writeEvent(string ownerPrefix)
3069
3086
// sanitizing member.Member.Name so that "ViewModel.SearchBreeds" becomes "ViewModel_SearchBreeds"
3070
3087
var sanitizedEventTarget = SanitizeResourceName ( eventTarget ) ;
3071
3088
3072
- ( string target , string weakReference , INamedTypeSymbol sourceType ) buildTargetContext ( )
3089
+ ( string target , string weakReference , IMethodSymbol targetMethod ) buildTargetContext ( )
3073
3090
{
3091
+ IMethodSymbol FindTargetMethodSymbol ( INamedTypeSymbol sourceType )
3092
+ {
3093
+ if ( eventTarget . Contains ( "." ) )
3094
+ {
3095
+ ITypeSymbol currentType = sourceType ;
3096
+
3097
+ var parts = eventTarget . Split ( '.' ) ;
3098
+
3099
+ for ( var i = 0 ; i < parts . Length - 1 ; i ++ )
3100
+ {
3101
+ var next = currentType . GetAllMembersWithName ( parts [ i ] ) . FirstOrDefault ( ) ;
3102
+
3103
+ currentType = next switch
3104
+ {
3105
+ IFieldSymbol fs => fs . Type ,
3106
+ IPropertySymbol ps => ps . Type ,
3107
+ null => throw new InvalidOperationException ( $ "Unable to find member { parts [ i ] } on type { currentType } ") ,
3108
+ _ => throw new InvalidOperationException ( $ "The field { next . Name } is not supported for x:Bind event binding")
3109
+ } ;
3110
+ }
3111
+
3112
+ var method = currentType . GetMethods ( ) . FirstOrDefault ( m => m . Name == parts . Last ( ) )
3113
+ ?? throw new InvalidOperationException ( $ "Failed to find { parts . Last ( ) } on { currentType } ") ;
3114
+
3115
+ return method ;
3116
+ }
3117
+ else
3118
+ {
3119
+ return sourceType . GetMethods ( ) . FirstOrDefault ( m => m . Name == eventTarget ) ;
3120
+ }
3121
+ }
3122
+
3074
3123
if ( isInsideDataTemplate . isInside )
3075
3124
{
3076
3125
var dataTypeObject = FindMember ( isInsideDataTemplate . xamlObject , "DataType" , XamlConstants . XamlXmlNamespace )
@@ -3083,32 +3132,44 @@ void writeEvent(string ownerPrefix)
3083
3132
// Use of __rootInstance is required to get the top-level DataContext, as it may be changed
3084
3133
// in the current visual tree by the user.
3085
3134
$ "(__rootInstance as global::Uno.UI.DataBinding.IWeakReferenceProvider).WeakReference",
3086
- dataTypeSymbol
3135
+ FindTargetMethodSymbol ( dataTypeSymbol )
3087
3136
) ;
3088
3137
}
3089
3138
else
3090
3139
{
3140
+
3091
3141
return (
3092
3142
$ "{ member . Member . Name } _{ sanitizedEventTarget } _That.Target as { _className . className } ",
3093
3143
$ "({ eventSource } as global::Uno.UI.DataBinding.IWeakReferenceProvider).WeakReference",
3094
- FindType ( _className . className )
3144
+ FindTargetMethodSymbol ( FindType ( _className . className ) )
3095
3145
) ;
3096
3146
}
3097
3147
}
3098
3148
3099
3149
var targetContext = buildTargetContext ( ) ;
3100
3150
3101
- var targetMethodHasParamters = targetContext . sourceType . GetMethods ( ) . FirstOrDefault ( m => m . Name == eventTarget ) ? . Parameters . Any ( ) ?? false ;
3151
+ var targetMethodHasParamters = targetContext . targetMethod ? . Parameters . Any ( ) ?? false ;
3102
3152
var xBindParams = targetMethodHasParamters ? parms : "" ;
3103
3153
3104
- //
3105
- // Generate a weak delegate, so the owner is not being held onto by the delegate. We can
3106
- // use the WeakReferenceProvider to get a self reference to avoid adding the cost of the
3107
- // creation of a WeakReference.
3108
- //
3109
- writer . AppendLineInvariant ( $ "var { member . Member . Name } _{ sanitizedEventTarget } _That = { targetContext . weakReference } ;") ;
3154
+ var builderName = $ "_{ ownerPrefix } _{ CurrentScope . xBindEventsHandlers . Count } _{ member . Member . Name } _{ sanitizedEventTarget } _Builder";
3155
+
3156
+ CurrentScope . xBindEventsHandlers . Add (
3157
+ new BackingFieldDefinition ( "global::System.Action" , builderName , Accessibility . Private )
3158
+ ) ;
3159
+
3160
+ using ( writer . BlockInvariant ( $ "{ builderName } = () => ") )
3161
+ {
3162
+ //
3163
+ // Generate a weak delegate, so the owner is not being held onto by the delegate. We can
3164
+ // use the WeakReferenceProvider to get a self reference to avoid adding the cost of the
3165
+ // creation of a WeakReference.
3166
+ //
3167
+ writer . AppendLineInvariant ( $ "var { member . Member . Name } _{ sanitizedEventTarget } _That = { targetContext . weakReference } ;") ;
3168
+
3169
+ writer . AppendLineInvariant ( $ "/* first level targetMethod:{ targetContext . targetMethod } */ { closureName } .{ member . Member . Name } += ({ parms } ) => ({ targetContext . target } )?.{ eventTarget } ({ xBindParams } );") ;
3170
+ }
3110
3171
3111
- writer . AppendLineInvariant ( $ "{ closureName } . { member . Member . Name } += ( { parms } ) => ( { targetContext . target } )?. { eventTarget } ( { xBindParams } ) ;") ;
3172
+ writer . AppendLineInvariant ( $ ";") ;
3112
3173
}
3113
3174
else
3114
3175
{
@@ -3123,7 +3184,7 @@ void writeEvent(string ownerPrefix)
3123
3184
//
3124
3185
writer . AppendLineInvariant ( $ "var { member . Member . Name } _{ sanitizedMemberValue } _That = ({ eventSource } as global::Uno.UI.DataBinding.IWeakReferenceProvider).WeakReference;") ;
3125
3186
3126
- writer . AppendLineInvariant ( $ "{ closureName } .{ member . Member . Name } += ({ parms } ) => ({ member . Member . Name } _{ sanitizedMemberValue } _That.Target as { _className . className } )?.{ member . Value } ({ parms } );") ;
3187
+ writer . AppendLineInvariant ( $ "/* second level */ { closureName } .{ member . Member . Name } += ({ parms } ) => ({ member . Member . Name } _{ sanitizedMemberValue } _That.Target as { _className . className } )?.{ member . Value } ({ parms } );") ;
3127
3188
}
3128
3189
}
3129
3190
else
0 commit comments