ViewModel Property getting set twice and null sometimes

GreekTreatGreekTreat Member ✭✭

I am having a problem with my Xamarin forms UI.
On Appearing of a UI
on my VM i call a function that does this
public void OnAppearing()
{
Task.Run(() =>
{
SetDataAsync().ConfigureAwait(false);
});
}
In SetDataAsync It goes to a services pulls a list a program codes.
Inside of SerDataAsync It Sets the program codes in the VM property
I have these two lines
ProgramCodes = new ObservableCollection(newCode);
SelectedGasProgramCode = newCode.First();

  private ObservableCollection<string> _programCodes;
        public ObservableCollection<string> programCodes
        {
            get { return _programCodes; }
            set
            {
                    SetProperty(ref _programCodes, value);             
            }
        }

        private string _selectedProgramCode;
        public string SelectedProgramCode
        {
            get { return _selectedProgramCode; }
            set
            {
                    SetProperty(ref _selectedProgramCode, value);
            }
        }

When I put a break point at Set_SelectedProgramCode
I see it when I want to set the value in SetDataAsync which is what I expected. and I see that in the call stack
BUT then I see it called again by Xamarin.Forms.Picker.ResetItems . I am sure what I am doing is wrong. But I am not sure how to do it correctly. I want to set the picker AND decided which item is the default selected.

Answers

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    What's this about?
    SetProperty(ref _programCodes, value);

    Typical property looks like this

            #region Comments (string)
            private string _Comments;
            public string Comments
            {
                get
                {
                    //if (_Comments == null) Comments = new string();
                    return _Comments;
                }
    
                set
                {
                    if (_Comments == value) return;
                    _Comments = value;
                    OnPropertyChanged();
                }
            }
            #endregion Comments  (string)
    

    What is your SetProperty method doing and why the ref to the backing field?

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    And your properties aren't raising notification of changes... So binding won't be of much good.

    I strongly suggest you work through some MVVM tutorials then return to this. It appears you have some misunderstandings about properties, binding, change notification and other foundation concepts required for MVVM to work correctly.

  • GreekTreatGreekTreat Member ✭✭

    @ClintStLaurent said:
    And your properties aren't raising notification of changes... So binding won't be of much good.

    I strongly suggest you work through some MVVM tutorials then return to this. It appears you have some misunderstandings about properties, binding, change notification and other foundation concepts required for MVVM to work correctly.

    I'm sorry that I gave you the impression I don't understand MVVM. I originally did MVVM with Silverlight back in 2011-2014. I haven't used it in a while. I am usings the Base Model from GrialUI that has a base Observable Object. which handles the triggers the PropertyChangedEvent

            protected bool SetProperty<T>(
                ref T backingStore, 
                T value,
                [CallerMemberName]string propertyName = "")
            {
                if (EqualityComparer<T>.Default.Equals(backingStore, value))
                {
                    return false;
                }
    
                backingStore = value;
                NotifyPropertyChanged(propertyName);
    
                return true;
            }
    
            protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
            {
                try
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
                catch (Exception ex)
                {
                    var properties = new Dictionary<string, string>
                    {
                         { "propertyName", propertyName}
                    };
                    Crashes.TrackError(ex, properties);
                }
            }
    

    After some research I have found the root cause. Some developers call this a Bug instead of a feature of the Picker. The problem is when you set the observable collection the Picker needs to reset it's self. i needs to set all the items in the list and because it's a new list it has to set the selected Items as null. this is why the selected property gets updated by the Picker. Also because the treads are doing things at different times. you can set the selected property first then have it override by the Picker.ResetItems method (race condition). The options I see are to not set the selected Item manually or never create a new ObservableCollection when you listy changes. just manual add/ remove items

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    The problem is when you set the observable collection the Picker needs to reset it's self.

    4 years in Xamarin and I never heard of or experienced that.

  • GreekTreatGreekTreat Member ✭✭

    @ClintStLaurent said:

    The problem is when you set the observable collection the Picker needs to reset it's self.

    4 years in Xamarin and I never heard of or experienced that.

    https://github.com/xamarin/Xamarin.Forms/issues/1879
    https://github.com/xamarin/Xamarin.Forms/issues/2032

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    Switch ItemSource (Model) and selected new SelectedItem
    Switch back to previous ItemSource (Model)

    BLUNTLY Well... When you do sh!t like that you're going to get what we call "unexpected results".
    You're not supposed to be switching itemsource in the first place. Again... go back and to MVVM right and you don't get this sort of [email protected]

    Title of the bug

    Forms Picker is setting SelectedItem=null after switching ItemSource

    Well... no kidding. Let's see. What would you expect? Walk it through with me.

    • You have a collection that is the item source of the Picker.
    • Of that collection one item is selected thus making the SelectedIndex corresponding to the index within the collection.
    • Then you take away the collection.
    • The SelectedIndex is going to get set to -1 because there is no longer a collection to index.

    What else could it be? There is no collection... therefore there is no SelectedIndex within that collection... therefore there is no SelectedItem based on the SelectedIndex based on the collection.

    Look at the alternative:

    • You have a collection of names: Fred, Wilma, Barney, Betty
    • The SelectedItem is Wilma, making SelectedIndex equal to 1
    • Then you change the ItemSource. Now its Ironman, Hulk, Spiderman, BlackWidow, Thor
      And what do you propose if you feel its a bug setting the selection to null... You don't change the SelectedItem so you still have Wilma as the selected item even though she's not in that collection?
      Or do you keep the index (of 1) and so when you change the collection suddenly your selected item becomes Hulk even though the user never actually picked Hulk?

    In other words its not a bug. Its the only reasonable way such a thing could actually be handled.

  • GreekTreatGreekTreat Member ✭✭

    I never stated this is a bug. What I asked is how do I deal with this case. The last line in my question is> "But I am not sure how to do it correctly. I want to set the picker AND decided which item is the default selected." . Yet you haven't yet helped me with the proper way of achieving this problem. All you know how to do is bash. Even in my previous post I figured out the root problem

    After some research I have found the root cause. Some developers call this a Bug instead of a feature of the Picker. The >problem is when you set the observable collection the Picker needs to reset it's self. i needs to set all the items in the list >and because it's a new list it has to set the selected Items as null. this is why the selected property gets updated by the >Picker. Also because the treads are doing things at different times. you can set the selected property first then have it >override by the Picker.ResetItems method (race condition). The options I see are to not set the selected Item manually or >never create a new ObservableCollection when you listy changes. just manual add/ remove items

    would you like to help or Bash?

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭
    edited May 15

    I never stated this is a bug.

    My mistake. You sighting it with links made me think you held that position. My bad.

    What I asked is how do I deal with this case.

    I don't know how many ways to say... Stop doing bad/wrong things and you won't get unexpected behavior.

    Yet you haven't yet helped me with the proper way of achieving this problem.

    When I said you need to read on how to do MVVM you replied you knew how to do MVVM. I'm not going to keep arguing the perspective that you don't. All I have to say is... A million other developers do MVVM as documented with out-of-the-box classes and it works fine for them. So I don't think its the a misbehavior in the controls or the framework.

    Again I'll suggest:
    First learn, then do. Work the tutorials of this decade for Xamarin and don't think that 2011 Silverlight has a bugs fart to do with how things are done here and now. Make a sample app and use the out-of-the-box classes and datatypes that work for the rest of the world before you go changing out to GrailUI or whatever. You've got so much going on that isn't standard that its near impossible to debug. Everyone else seems to do just fine with making their class and inheriting from BindableObject, without going off into left field with some other 3rd party base class.
    public class myCoolObject : BindableObject - See, easy.

    Without exaggeration I've had a couple hundred people tell me that actually working my tutorials helps them grasp MVVM in the 21st century. What have you got to loose: A couple hours of your day? You're loosing that anyway.
    http://redpillxamarin.com/2018/03/12/2018-101-vs2017-new-solution/

Sign In or Register to comment.