Reputation: 25
I believe that OnElementChanged is supposed to be called twice: once when the control is created and once when it is disposed. This works as expected for my iOS custom renderer but not in Android custom renderer.
In iOS when a page is dipslayed e.NewElement is the control and e.OldElement is null. When the next page is shown, this previous control seems disposed of as e.NewElement is null and e.OldElement is that control. OnElementChanged is called for the new controls in the new page. This is not the case for Android.
In Android, each time a new screen with the controls is displayed, OnElementChanged is called with e.OldElement as null and e.NewElement as the control (as expected). However, when the display is changed to a new screen, the OnElementChanged method is not called for the previous controls with e.NewElement as null. Instead, the OnElementChanged methods for the new controls on the new page are called.
Is there a reason why this issue is happening specifically in Android? Are there any reasons why this could be happening?
My purpose is to safely unhook the event once that control is disposed of.
iOS:
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace iOS.Renderers
{
public class MyEntryRenderer: EntryRenderer
{
private UIButton _myButton = null;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
// update control UI
...
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
_myButton .TouchUpInside -= OnClearButtonTouched;
}
if (e.NewElement != null)
{
if (_myButton == null)
{
// create button
_myButton = ...;
}
// Subscribe
_myButton.TouchUpInside += OnClearButtonTouched;
}
}
...
}
}
Android:
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace Android.Renderers
{
public class MyEntryRenderer: EntryRenderer
{
private FormsEditText _formsEditText;
private Drawable _leftDrawable = null;
public MyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
// update control UI
...
base.OnElementChanged(e);
// set appropriate event handler for when text is cleared
if (_leftDrawable == null) {
// get appropriate search drawable
_leftDrawable = ...;
}
if (e.OldElement != null)
{
// Unsubscribe
Control.AfterTextChanged -= AfterEntryTextChanged;
}
if (e.NewElement != null)
{
if (Control == null)
{
_formsEditText = new FormsEditText(Context);
SetNativeControl(_formsEditText);
}
// Subscribe
Control.AfterTextChanged += AfterEntryTextChanged;
}
}
...
}
}
Upvotes: 1
Views: 1679
Reputation: 2995
On Android unhook the event in Dispose
:
bool _disposed;
protected override void Dispose(bool disposing)
{
if (_disposed)
return;
_disposed = true;
if (Control != null && disposing)
{
_myButton.TouchUpInside -= OnClearButtonTouched;
}
base.Dispose(disposing);
}
See also EntryRenderer and [Android] Effects don't detach and OnElementchanged(null) is never called #2520
Upvotes: 3