4
4
using System . Reflection ;
5
5
using System . Linq ;
6
6
using Xamarin . Forms ;
7
+ using Android . App ;
7
8
8
9
namespace AiForms . Effects . Droid
9
10
{
@@ -14,7 +15,6 @@ public abstract class AiEffectBase : PlatformEffect
14
15
15
16
IVisualElementRenderer _renderer ;
16
17
bool _isDisposed = false ;
17
- WeakReference < Page > _pageRef ;
18
18
19
19
protected bool IsDisposed {
20
20
get {
@@ -47,28 +47,32 @@ protected bool IsNullOrDisposed{
47
47
protected override void OnAttached ( )
48
48
{
49
49
var visual = Element as VisualElement ;
50
+ var page = visual . Navigation . NavigationStack . LastOrDefault ( ) ;
51
+ if ( page == null )
52
+ {
53
+ page = visual . Navigation . ModalStack . LastOrDefault ( ) ;
54
+ if ( page == null ) {
55
+ // In case the element in DataTemplate, NavigationProxycan't be got.
56
+ // Instead of it, the page dismissal is judged by whether the BindingContext is null.
57
+ Element . BindingContextChanged += BindingContextChanged ;
58
+ return ;
59
+ }
60
+ }
50
61
51
- var page = visual . Navigation . NavigationStack . LastOrDefault ( ) ??
52
- visual . Navigation . ModalStack . LastOrDefault ( ) ;
53
-
54
- if ( page == null )
55
- return ;
56
-
57
- page . Disappearing += Page_Disappearing ;
58
-
59
- _pageRef = new WeakReference < Page > ( page ) ;
62
+ // To call certainly a OnDetached method when the page is popped,
63
+ // it executes the process removing all the effects in the page at once with Attached bindable property.
64
+ if ( ! GetIsRegistered ( page ) )
65
+ {
66
+ SetIsRegistered ( page , true ) ;
67
+ }
60
68
}
61
69
62
70
protected override void OnDetached ( )
63
71
{
64
72
System . Diagnostics . Debug . WriteLine ( $ "Detached { GetType ( ) . Name } from { Element . GetType ( ) . FullName } ") ;
65
- if ( _pageRef != null && _pageRef . TryGetTarget ( out var page ) )
66
- {
67
- page . Disappearing -= Page_Disappearing ;
68
- }
73
+ Element . BindingContextChanged -= BindingContextChanged ;
69
74
70
75
_renderer = null ;
71
- _pageRef = null ;
72
76
}
73
77
74
78
@@ -125,16 +129,95 @@ Func<object, object> CreateGetField(Type t)
125
129
return lambda . Compile ( ) ;
126
130
}
127
131
128
- void Page_Disappearing ( object sender , EventArgs e )
132
+ void BindingContextChanged ( object sender , EventArgs e )
129
133
{
134
+ if ( Element . BindingContext != null )
135
+ return ;
136
+
130
137
// For Android, when a page is popped, OnDetached is automatically not called. (when iOS, it is called)
131
- // So, made the Page.Disappearing event subscribe in advance
132
- // and make the effect manually removed when the page is popped.
133
- if ( IsAttached && ! IsDisposed )
138
+ // So, made the BindingContextChanged event subscribe in advance
139
+ // and make the effect manually removed when the BindingContext is null.
140
+ // However, there is the problem that it isn't called when the BindingContext remains null all along.
141
+ // The above solution is to use NavigationPage.Popped or Application.ModalPopping event.
142
+ // That's why the following code runs only when the element is in a DataTemplate.
143
+ if ( IsAttached )
134
144
{
135
145
var toRemove = Element . Effects . OfType < AiRoutingEffectBase > ( ) . FirstOrDefault ( x => x . EffectId == ResolveId ) ;
136
146
Device . BeginInvokeOnMainThread ( ( ) => Element . Effects . Remove ( toRemove ) ) ;
137
147
}
138
148
}
149
+
150
+ internal static readonly BindableProperty IsRegisteredProperty =
151
+ BindableProperty . CreateAttached (
152
+ "IsRegistered" ,
153
+ typeof ( bool ) ,
154
+ typeof ( AiEffectBase ) ,
155
+ default ( bool ) ,
156
+ propertyChanged : IsRegisteredPropertyChanged
157
+ ) ;
158
+
159
+ internal static void SetIsRegistered ( BindableObject view , bool value )
160
+ {
161
+ view . SetValue ( IsRegisteredProperty , value ) ;
162
+ }
163
+
164
+ internal static bool GetIsRegistered ( BindableObject view )
165
+ {
166
+ return ( bool ) view . GetValue ( IsRegisteredProperty ) ;
167
+ }
168
+
169
+ static void IsRegisteredPropertyChanged ( BindableObject bindable , object oldValue , object newValue )
170
+ {
171
+ if ( ! ( bool ) newValue ) return ;
172
+
173
+ var page = bindable as Page ;
174
+
175
+ if ( page . Parent is NavigationPage navi )
176
+ {
177
+ navi . Popped += NaviPopped ;
178
+ }
179
+ else
180
+ {
181
+ Xamarin . Forms . Application . Current . ModalPopping += ModalPopping ;
182
+ }
183
+
184
+ void NaviPopped ( object sender , NavigationEventArgs e )
185
+ {
186
+ if ( e . Page != page )
187
+ return ;
188
+
189
+ navi . Popped -= NaviPopped ;
190
+
191
+ RemoveEffects ( ) ;
192
+ }
193
+
194
+ void ModalPopping ( object sender , ModalPoppingEventArgs e )
195
+ {
196
+ if ( e . Modal != page )
197
+ return ;
198
+
199
+ Xamarin . Forms . Application . Current . ModalPopping -= ModalPopping ;
200
+
201
+ RemoveEffects ( ) ;
202
+ }
203
+
204
+ void RemoveEffects ( )
205
+ {
206
+ foreach ( var child in page . Descendants ( ) )
207
+ {
208
+ foreach ( var effect in child . Effects . OfType < AiRoutingEffectBase > ( ) )
209
+ {
210
+ Device . BeginInvokeOnMainThread ( ( ) => child . Effects . Remove ( effect ) ) ;
211
+ }
212
+ }
213
+
214
+ foreach ( var effect in page . Effects . OfType < AiRoutingEffectBase > ( ) )
215
+ {
216
+ Device . BeginInvokeOnMainThread ( ( ) => page . Effects . Remove ( effect ) ) ;
217
+ }
218
+
219
+ page . ClearValue ( IsRegisteredProperty ) ;
220
+ }
221
+ }
139
222
}
140
223
}
0 commit comments