Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 91519

Bug in Picker? Observing weird behavior (code included)

$
0
0

I am having some trouble updating a Picker with new content and wondering if I'm experiencing a bug?

I have a xaml page with two pickers; Picker1 and Picker2. They are bound to a viewmodel using the BindablePicker class that have been posted/discussed in this forum a number of times. The properties are:

Item1 (string)
ItemList1 (ObservableCollection)
Item2 (string)
ItemList2 (ObservableCollection)

I initialize Picker1 with data and in the setter property of the Selected item of Picker1 I call a method to initialize Picker2 with data.

The problem is that this only works every SECOND time.
Every second time Item2 is set to null.

This is my test code to initialize Picker2:

    void UpdatePicker2()
    {
        if (Item1.Equals ("Picker1-a")) {
            var itemList = new ObservableCollection<string> () { "a", "b", "c" };
            ItemList2 = itemList;
        } else if (Item1.Equals ("Picker1-b")) {
            var itemList = new ObservableCollection<string> () { "aa", "bb", "cc" };
            ItemList2 = itemList;
        } else {
            var itemList = new ObservableCollection<string> () { "aaa", "bbb", "ccc" };
            ItemList2 = itemList;
        }
        Item2 = ItemList2 [0];
    }

Please note that if I just clear the existing collection and add new items - then nothing is working at all. Not even every second time. Ie. like this:

            ItemList2.Clear ();
            ItemList2.Add ("a");
            ItemList2.Add ("b");
            ItemList2.Add ("c");

instead of:

            var itemList = new ObservableCollection<string> () { "a", "b", "c" };
            ItemList2 = itemList;

If I setting a breakpoint in the setter of Item2, I see the property is set twice in both cases (both when it's working and when it's not).

Here are the two call-stacks in the case of not working:

1) This is the set that I do in UpdatePicker2() as expected:

PickerBug.ViewModel.set_Item2 (value="aa") in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:35
PickerBug.ViewModel.UpdatePicker2 () in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:93
PickerBug.ViewModel.set_Item1 (value="Picker1-b") in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:15
System.Reflection.MonoMethod.InternalInvoke () in 

[... rest not important..]

2) This is coming afterward:

PickerBug.ViewModel.set_Item2 (value=(null)) in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:35 System.Reflection.MonoMethod.InternalInvoke () in 
Xamarin.Forms.BindingExpression.ApplyCore (sourceObject={PickerBug.ViewModel}, target={PickerBug.BindablePicker}, property=SelectedItem, fromTarget=true) in 
Xamarin.Forms.BindingExpression.Apply (fromTarget=true) in 
Xamarin.Forms.Binding.Apply (fromTarget=true) in 
Xamarin.Forms.BindableObject.SetValueActual (property=SelectedItem, value=(null), currentlyApplying=false, clearBindings=true, raiseOnEqual=false) in 
Xamarin.Forms.BindableObject.SetValueCore (property=SelectedItem, value=(null), clearBindings=true, raiseOnEqual=false, checkaccess=true) in 
Xamarin.Forms.BindableObject.SetValue (property=SelectedItem, value=(null), checkaccess=true) in 
Xamarin.Forms.BindableObject.SetValue (property=SelectedItem, value=(null)) in 
PickerBug.BindablePicker.set_SelectedItem (value=(null)) in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/BindablePicker.cs:29
PickerBug.BindablePicker.OnSelectedIndexChanged (sender={PickerBug.BindablePicker}, eventArgs={System.EventArgs}) in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/BindablePicker.cs:50
Xamarin.Forms.Picker.<.cctor>b__0 (bindable={PickerBug.BindablePicker}, oldvalue=0, newvalue=-1) in 
Xamarin.Forms.BindableObject.SetValueActual (property=SelectedIndex, value=-1, currentlyApplying=false, clearBindings=true, raiseOnEqual=false) in 
Xamarin.Forms.BindableObject.SetValueCore (property=SelectedIndex, value=-1, clearBindings=true, raiseOnEqual=false, checkaccess=true) in 
Xamarin.Forms.BindableObject.SetValue (property=SelectedIndex, value=-1, checkaccess=true) in 
Xamarin.Forms.BindableObject.SetValue (property=SelectedIndex, value=-1) in 
Xamarin.Forms.Picker.set_SelectedIndex (value=-1) in 
Xamarin.Forms.Picker.OnItemsCollectionChanged (sender=Count=0, e={System.Collections.Specialized.NotifyCollectionChangedEventArgs}) in 
System.Collections.ObjectModel.ObservableCollection<string>.OnCollectionChanged (e={System.Collections.Specialized.NotifyCollectionChangedEventArgs}) in
///Library/Frameworks/Xamarin.iOS.framework/Versions/8.4.0.43/src/mono/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs:161
System.Collections.ObjectModel.ObservableCollection<string>.ClearItems () in
///Library/Frameworks/Xamarin.iOS.framework/Versions/8.4.0.43/src/mono/mcs/class/System/System.Collections.ObjectModel/ObservableCollection.cs:120
System.Collections.ObjectModel.Collection<string>.Clear () in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Collections.ObjectModel/Collection.cs:86
PickerBug.BindablePicker.OnItemsSourceChanged (bindable={PickerBug.BindablePicker}, oldvalue=Count=3, newvalue=Count=3) in
/Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/BindablePicker.cs:35
Xamarin.Forms.BindableProperty.<>c__DisplayClass4<PickerBug.BindablePicker,System.Collections. (bindable={PickerBug.BindablePicker}, oldValue=Count=3, newValue=Count=3) in
Xamarin.Forms.BindableObject.SetValueActual (property=ItemsSource, value=Count=3, currentlyApplying=false, clearBindings=false, raiseOnEqual=false) in 
Xamarin.Forms.BindableObject.SetValueCore (property=ItemsSource, value=Count=3, clearBindings=false, raiseOnEqual=false, checkaccess=true) in 
Xamarin.Forms.BindingExpression.ApplyCore (sourceObject={PickerBug.ViewModel}, target={PickerBug.BindablePicker}, property=ItemsSource, fromTarget=false) in 
Xamarin.Forms.BindingExpression.Apply (fromTarget=false) in 
Xamarin.Forms.BindingExpression.BindingExpressionPart.<PropertyChanged>b__12 () in 
MonoTouch.Foundation.NSAsyncActionDispatcher.Apply () in /Developer/MonoTouch/Source/maccore/src/Foundation/NSAction.cs:164
MonoTouch.UIKit.UIApplication.UIApplicationMain () in 
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principal=0x0, delegate=0x7be60120) in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:62
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principalClassName=(null), delegateClassName="AppDelegate") in
/Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:46
PickerBug.iOS.Application.Main (args={string[0]}) in /Users/amor/code/Xamarin/_testing/PickerBug/iOS/Main.cs:17

Here are the two call-stacks in the case of it working:

1) This is the set that I do in UpdatePicker2() as expected: (same as above)

PickerBug.ViewModel.set_Item2 (value="aa") in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:35
PickerBug.ViewModel.UpdatePicker2 () in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:93
PickerBug.ViewModel.set_Item1 (value="Picker1-b") in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:15
System.Reflection.MonoMethod.InternalInvoke () in

[... rest not important..]

2) This is coming afterward:

PickerBug.ViewModel.set_Item2 (value="aaa") in /Users/amor/code/Xamarin/_testing/PickerBug/PickerBug/ViewModel.cs:35
System.Reflection.MonoMethod.InternalInvoke () in 
Xamarin.Forms.BindingExpression.ApplyCore (sourceObject={PickerBug.ViewModel}, target={PickerBug.BindablePicker}, property=SelectedItem, fromTarget=true) in 
Xamarin.Forms.BindingExpression.Apply (fromTarget=true) in 
Xamarin.Forms.Binding.Apply (fromTarget=true) in 
Xamarin.Forms.BindableObject.SetValueActual (property=SelectedItem, value="aaa", currentlyApplying=false, clearBindings=false, raiseOnEqual=false) in 
Xamarin.Forms.BindableObject.SetValueCore (property=SelectedItem, value="aaa", clearBindings=false, raiseOnEqual=false, checkaccess=true) in 
Xamarin.Forms.BindingExpression.ApplyCore (sourceObject={PickerBug.ViewModel}, target={PickerBug.BindablePicker}, property=SelectedItem, fromTarget=false) in 
Xamarin.Forms.BindingExpression.Apply (fromTarget=false) in 
Xamarin.Forms.BindingExpression.BindingExpressionPart.<PropertyChanged>b__12 () in 
MonoTouch.Foundation.NSAsyncActionDispatcher.Apply () in /Developer/MonoTouch/Source/maccore/src/Foundation/NSAction.cs:164
MonoTouch.UIKit.UIApplication.UIApplicationMain () in 
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principal=0x0, delegate=0x7969a780) in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:62
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principalClassName=(null), delegateClassName="AppDelegate") in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:46
PickerBug.iOS.Application.Main (args={string[0]}) in /Users/amor/code/Xamarin/_testing/PickerBug/iOS/Main.cs:17

Another curious thing, if I set a breakpoint in BindablePicker :

    private static void OnItemsSourceChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue)
    {
        var picker = bindable as BindablePicker;
        picker.Items.Clear(); // EG SET BREAKPOINT HERE
        if (newvalue != null)
        {
            foreach (var item in newvalue)
            {
                picker.Items.Add(item.ToString());
            }
        }
    } // AND HERE

Then I can see that the second call to Item2 setter is executed at two different times. In the case of it "not working" the call is happening immediately after the picker.Items.Clear() and in the case of it working the call comes in after the OnItemsSourceChanged method has completely finished.

This makes me suspicious of some async behavior - but all my code should execute synchronous.

Any insights or ideas?

I have attached a complete (very minimal) test project, with a xaml page with the two pickers, a viewmodel and that's it.

Thanks


Viewing all articles
Browse latest Browse all 91519

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>