Bug 24871 - Picker value doesn't get updated when Android "reuses" an old control
Summary: Picker value doesn't get updated when Android "reuses" an old control
Status: RESOLVED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 1.2.3
Hardware: All All
: Normal normal
Target Milestone: ---
Assignee: Rui Marinho
URL:
Depends on:
Blocks:
 
Reported: 2014-11-26 21:40 UTC by Nathan B. Evans
Modified: 2015-06-29 13:42 UTC (History)
6 users (show)

Tags: AC picker
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Nathan B. Evans 2014-11-26 21:40:52 UTC
I have identified a bug in the Picker control, particularly the Android renderer (and possibly other platforms, but I haven't checked).

Basically when OnElementChanged is raised, at no point is the UpdatePicker()  (a private method) called to ensure that both the Title and SelectedIndex are updated.

On our application, which generates *dynamic* forms (important note: we don't use data binding for this) including hiding and showing of control elements, this causes an issue where the selected index is not updated and a sort of "ghost selected value" appears on the TextView. When the picker is tapped, the correct value is shown on the list spinner. But obviously, the "ghost selected value" is incredibly confusing for the user.

It appears to be a side affect of the way Android likes to "reuse" old native controls. An old control is being reused, correctly, for performance reasons, but Xamarin Forms is not updating the values of this reused native control.

Using JustDecompile, we have checked and compared PickerRenderer against other types of renderers in the Android Renderers assembly and all those others call their respective Update*() method from the OnElementChanged. I believe the Picker is the only control we have experienced this issue with on our application. It seems this may be an inadvertent inconsistency i.e. a bug.

We have temporarily fixed it with this simple renderer subclass, as follows, but it would be good if Xamarin Forms team could review this issue and bake in a proper long term fix.


    [assembly: ExportRenderer(typeof(Picker), typeof(HackFix20141127PickerRenderer))]

    public sealed class HackFix20141127PickerRenderer : PickerRenderer {
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e) {
            base.OnElementChanged(e);

            if (e.OldElement != null) {
                OnElementPropertyChanged(this, new PropertyChangedEventArgs(Picker.TitleProperty.PropertyName));
                OnElementPropertyChanged(this, new PropertyChangedEventArgs(Picker.SelectedIndexProperty.PropertyName));
            }
        }
    }
Comment 1 Nathan B. Evans 2014-11-26 21:49:25 UTC
Here is the offending code from JustDecompile:

        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement != null)
            {
                ((ObservableList<string>)e.OldElement.Items).remove_CollectionChanged(new NotifyCollectionChangedEventHandler(this, PickerRenderer.RowsCollectionChanged));
            }
            if (e.NewElement != null)
            {
                ((ObservableList<string>)e.NewElement.Items).add_CollectionChanged(new NotifyCollectionChangedEventHandler(this, PickerRenderer.RowsCollectionChanged));
            }
            if (e.OldElement == null)
            {
                EditText editText = new EditText(base.Context)
                {
                    Focusable = false,
                    Clickable = true,
                    Tag = this
                };
                EditText editText1 = editText;
                editText1.SetOnClickListener(PickerRenderer.PickerListener.Instance);
                base.SetNativeControl(editText1);
                this.UpdatePicker(); // TODO: XAMARIN FORMS TEAM PLEASE MOVE THIS SINGLE LINE OF CODE THAT CALLS UpdatePicker() TO BE BELOW THE NEXT CLOSING BRACE.
            }
        }
Comment 2 Rui Marinho 2015-06-15 11:30:44 UTC
Should be fixed in 1.4.3 final.