Binding to MvxSpinner SelectedItem property not working












2















I use a MvxSpinner to show country phone prefixes in a combobox in a MvvmCross for Xamarin app. I can bind to the ItemsSource property correctly, so I can see the list of my prefixes but when I assign the property in my view model that is bind to the SelectedItem property of the MvxSpinner, it won't work and will always show the first element in the list as the selected item.



The way I do it is the following. In my ViewModel I get the user data from the server and assign the properties for Country and PhonePrefix. Then I get the list of all countries and prefixes also from server and bind them to the list properties that are binded to the ItemSource properties of the respewctive MvxSpinners (simplified):



    public string PhonePrefix { get; set; }
public string PhoneNumber { get; set; }
public Country Country { get; set; } = new Country();

public List<Country> Countries { get; set; } = new List<Country>();
public List<string> Prefixes { get; set; } = new List<string>();

private async Task GetUserData()
{
try
{
var userDataResult = await _registrationService.GetLoggedInUserData();

if (userDataResult != null)
{
if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
{
Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
}
else
{

PhonePrefix = userDataResult.user.country_code_phone;
PhoneNumber = userDataResult.user.phone;
Country.id = userDataResult.user.person.addresses[0].country_id;
Country.name = userDataResult.user.person.addresses[0].country_name;
}
}
}
catch (Exception e)
{
Log.Error<RegistrationViewModel>("GetUserData", e);
}
}

/// <summary>
/// Populates the view model properties for Countries and Prefixes with information retrieved from the server
/// </summary>
private void ProcessFormData()
{
if (_registrationFormData != null)
{
Countries = _registrationFormData.Countries?.ToList();
var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

var prefixes = new List<string>();
if (Countries != null)
{
foreach (var country in Countries)
{
//spinner binding doesn't allow null values
if (country.phone_prefix != null)
{
prefixes.Add(country.phone_prefix);
}
}
}

//we need to assign the binded Prefixes at once otherwise the binding for the ItemSource fails
Prefixes = prefixes;
PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;
}
}


And in the axml layout:



    <MvxSpinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="25dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:id="@+id/spnrCountry"
local:MvxBind="ItemsSource Countries; SelectedItem Country"/>
<MvxSpinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="25dp"
android:layout_marginBottom="10dp"
android:id="@+id/spnrPrefix"
local:MvxBind="ItemsSource Prefixes; SelectedItem PhonePrefix"/>


On the output window I can see the following error regarding MvxBinding:



(MvxBind) Null values not permitted in spinner SelectedItem binding currently


I debugged and I never have any Null values in the lists or in the properties I bind to the ItemSource and SelectedItem properties of the MvxSpinner.



Actually the Countries ItemSource and SelectedItem work properly so if user saved it's country to be Argentina, when I load it's data the selected item in the spinner will be Argentina. Note that I use a Country entity like that:



public class Country
{
public int id { get; set; }
public bool favorite { get; set; }
public string name { get; set; }
public string name_de { get; set; }
public string code { get; set; }
public int rzl_code { get; set; }
public string phone_prefix { get; set; }
public string updated_at { get; set; }
public string created_at { get; set; }

public override string ToString()
{
return name;
}
}


I also tried to make the phone prefix in it's own entity wrapping a string value but it didn't work either.



Does anybody knows what I'm doing wrong? Why for the Countries it's working and for the prefixes not?



I use PropertyChanged.Fody.



Thanks!










share|improve this question





























    2















    I use a MvxSpinner to show country phone prefixes in a combobox in a MvvmCross for Xamarin app. I can bind to the ItemsSource property correctly, so I can see the list of my prefixes but when I assign the property in my view model that is bind to the SelectedItem property of the MvxSpinner, it won't work and will always show the first element in the list as the selected item.



    The way I do it is the following. In my ViewModel I get the user data from the server and assign the properties for Country and PhonePrefix. Then I get the list of all countries and prefixes also from server and bind them to the list properties that are binded to the ItemSource properties of the respewctive MvxSpinners (simplified):



        public string PhonePrefix { get; set; }
    public string PhoneNumber { get; set; }
    public Country Country { get; set; } = new Country();

    public List<Country> Countries { get; set; } = new List<Country>();
    public List<string> Prefixes { get; set; } = new List<string>();

    private async Task GetUserData()
    {
    try
    {
    var userDataResult = await _registrationService.GetLoggedInUserData();

    if (userDataResult != null)
    {
    if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
    {
    Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
    }
    else
    {

    PhonePrefix = userDataResult.user.country_code_phone;
    PhoneNumber = userDataResult.user.phone;
    Country.id = userDataResult.user.person.addresses[0].country_id;
    Country.name = userDataResult.user.person.addresses[0].country_name;
    }
    }
    }
    catch (Exception e)
    {
    Log.Error<RegistrationViewModel>("GetUserData", e);
    }
    }

    /// <summary>
    /// Populates the view model properties for Countries and Prefixes with information retrieved from the server
    /// </summary>
    private void ProcessFormData()
    {
    if (_registrationFormData != null)
    {
    Countries = _registrationFormData.Countries?.ToList();
    var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
    Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

    var prefixes = new List<string>();
    if (Countries != null)
    {
    foreach (var country in Countries)
    {
    //spinner binding doesn't allow null values
    if (country.phone_prefix != null)
    {
    prefixes.Add(country.phone_prefix);
    }
    }
    }

    //we need to assign the binded Prefixes at once otherwise the binding for the ItemSource fails
    Prefixes = prefixes;
    PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;
    }
    }


    And in the axml layout:



        <MvxSpinner
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="25dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="10dp"
    android:id="@+id/spnrCountry"
    local:MvxBind="ItemsSource Countries; SelectedItem Country"/>
    <MvxSpinner
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="25dp"
    android:layout_marginBottom="10dp"
    android:id="@+id/spnrPrefix"
    local:MvxBind="ItemsSource Prefixes; SelectedItem PhonePrefix"/>


    On the output window I can see the following error regarding MvxBinding:



    (MvxBind) Null values not permitted in spinner SelectedItem binding currently


    I debugged and I never have any Null values in the lists or in the properties I bind to the ItemSource and SelectedItem properties of the MvxSpinner.



    Actually the Countries ItemSource and SelectedItem work properly so if user saved it's country to be Argentina, when I load it's data the selected item in the spinner will be Argentina. Note that I use a Country entity like that:



    public class Country
    {
    public int id { get; set; }
    public bool favorite { get; set; }
    public string name { get; set; }
    public string name_de { get; set; }
    public string code { get; set; }
    public int rzl_code { get; set; }
    public string phone_prefix { get; set; }
    public string updated_at { get; set; }
    public string created_at { get; set; }

    public override string ToString()
    {
    return name;
    }
    }


    I also tried to make the phone prefix in it's own entity wrapping a string value but it didn't work either.



    Does anybody knows what I'm doing wrong? Why for the Countries it's working and for the prefixes not?



    I use PropertyChanged.Fody.



    Thanks!










    share|improve this question



























      2












      2








      2








      I use a MvxSpinner to show country phone prefixes in a combobox in a MvvmCross for Xamarin app. I can bind to the ItemsSource property correctly, so I can see the list of my prefixes but when I assign the property in my view model that is bind to the SelectedItem property of the MvxSpinner, it won't work and will always show the first element in the list as the selected item.



      The way I do it is the following. In my ViewModel I get the user data from the server and assign the properties for Country and PhonePrefix. Then I get the list of all countries and prefixes also from server and bind them to the list properties that are binded to the ItemSource properties of the respewctive MvxSpinners (simplified):



          public string PhonePrefix { get; set; }
      public string PhoneNumber { get; set; }
      public Country Country { get; set; } = new Country();

      public List<Country> Countries { get; set; } = new List<Country>();
      public List<string> Prefixes { get; set; } = new List<string>();

      private async Task GetUserData()
      {
      try
      {
      var userDataResult = await _registrationService.GetLoggedInUserData();

      if (userDataResult != null)
      {
      if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
      {
      Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
      }
      else
      {

      PhonePrefix = userDataResult.user.country_code_phone;
      PhoneNumber = userDataResult.user.phone;
      Country.id = userDataResult.user.person.addresses[0].country_id;
      Country.name = userDataResult.user.person.addresses[0].country_name;
      }
      }
      }
      catch (Exception e)
      {
      Log.Error<RegistrationViewModel>("GetUserData", e);
      }
      }

      /// <summary>
      /// Populates the view model properties for Countries and Prefixes with information retrieved from the server
      /// </summary>
      private void ProcessFormData()
      {
      if (_registrationFormData != null)
      {
      Countries = _registrationFormData.Countries?.ToList();
      var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
      Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

      var prefixes = new List<string>();
      if (Countries != null)
      {
      foreach (var country in Countries)
      {
      //spinner binding doesn't allow null values
      if (country.phone_prefix != null)
      {
      prefixes.Add(country.phone_prefix);
      }
      }
      }

      //we need to assign the binded Prefixes at once otherwise the binding for the ItemSource fails
      Prefixes = prefixes;
      PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;
      }
      }


      And in the axml layout:



          <MvxSpinner
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:minHeight="25dp"
      android:layout_marginTop="5dp"
      android:layout_marginBottom="10dp"
      android:id="@+id/spnrCountry"
      local:MvxBind="ItemsSource Countries; SelectedItem Country"/>
      <MvxSpinner
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:minHeight="25dp"
      android:layout_marginBottom="10dp"
      android:id="@+id/spnrPrefix"
      local:MvxBind="ItemsSource Prefixes; SelectedItem PhonePrefix"/>


      On the output window I can see the following error regarding MvxBinding:



      (MvxBind) Null values not permitted in spinner SelectedItem binding currently


      I debugged and I never have any Null values in the lists or in the properties I bind to the ItemSource and SelectedItem properties of the MvxSpinner.



      Actually the Countries ItemSource and SelectedItem work properly so if user saved it's country to be Argentina, when I load it's data the selected item in the spinner will be Argentina. Note that I use a Country entity like that:



      public class Country
      {
      public int id { get; set; }
      public bool favorite { get; set; }
      public string name { get; set; }
      public string name_de { get; set; }
      public string code { get; set; }
      public int rzl_code { get; set; }
      public string phone_prefix { get; set; }
      public string updated_at { get; set; }
      public string created_at { get; set; }

      public override string ToString()
      {
      return name;
      }
      }


      I also tried to make the phone prefix in it's own entity wrapping a string value but it didn't work either.



      Does anybody knows what I'm doing wrong? Why for the Countries it's working and for the prefixes not?



      I use PropertyChanged.Fody.



      Thanks!










      share|improve this question
















      I use a MvxSpinner to show country phone prefixes in a combobox in a MvvmCross for Xamarin app. I can bind to the ItemsSource property correctly, so I can see the list of my prefixes but when I assign the property in my view model that is bind to the SelectedItem property of the MvxSpinner, it won't work and will always show the first element in the list as the selected item.



      The way I do it is the following. In my ViewModel I get the user data from the server and assign the properties for Country and PhonePrefix. Then I get the list of all countries and prefixes also from server and bind them to the list properties that are binded to the ItemSource properties of the respewctive MvxSpinners (simplified):



          public string PhonePrefix { get; set; }
      public string PhoneNumber { get; set; }
      public Country Country { get; set; } = new Country();

      public List<Country> Countries { get; set; } = new List<Country>();
      public List<string> Prefixes { get; set; } = new List<string>();

      private async Task GetUserData()
      {
      try
      {
      var userDataResult = await _registrationService.GetLoggedInUserData();

      if (userDataResult != null)
      {
      if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
      {
      Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
      }
      else
      {

      PhonePrefix = userDataResult.user.country_code_phone;
      PhoneNumber = userDataResult.user.phone;
      Country.id = userDataResult.user.person.addresses[0].country_id;
      Country.name = userDataResult.user.person.addresses[0].country_name;
      }
      }
      }
      catch (Exception e)
      {
      Log.Error<RegistrationViewModel>("GetUserData", e);
      }
      }

      /// <summary>
      /// Populates the view model properties for Countries and Prefixes with information retrieved from the server
      /// </summary>
      private void ProcessFormData()
      {
      if (_registrationFormData != null)
      {
      Countries = _registrationFormData.Countries?.ToList();
      var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
      Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

      var prefixes = new List<string>();
      if (Countries != null)
      {
      foreach (var country in Countries)
      {
      //spinner binding doesn't allow null values
      if (country.phone_prefix != null)
      {
      prefixes.Add(country.phone_prefix);
      }
      }
      }

      //we need to assign the binded Prefixes at once otherwise the binding for the ItemSource fails
      Prefixes = prefixes;
      PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;
      }
      }


      And in the axml layout:



          <MvxSpinner
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:minHeight="25dp"
      android:layout_marginTop="5dp"
      android:layout_marginBottom="10dp"
      android:id="@+id/spnrCountry"
      local:MvxBind="ItemsSource Countries; SelectedItem Country"/>
      <MvxSpinner
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:minHeight="25dp"
      android:layout_marginBottom="10dp"
      android:id="@+id/spnrPrefix"
      local:MvxBind="ItemsSource Prefixes; SelectedItem PhonePrefix"/>


      On the output window I can see the following error regarding MvxBinding:



      (MvxBind) Null values not permitted in spinner SelectedItem binding currently


      I debugged and I never have any Null values in the lists or in the properties I bind to the ItemSource and SelectedItem properties of the MvxSpinner.



      Actually the Countries ItemSource and SelectedItem work properly so if user saved it's country to be Argentina, when I load it's data the selected item in the spinner will be Argentina. Note that I use a Country entity like that:



      public class Country
      {
      public int id { get; set; }
      public bool favorite { get; set; }
      public string name { get; set; }
      public string name_de { get; set; }
      public string code { get; set; }
      public int rzl_code { get; set; }
      public string phone_prefix { get; set; }
      public string updated_at { get; set; }
      public string created_at { get; set; }

      public override string ToString()
      {
      return name;
      }
      }


      I also tried to make the phone prefix in it's own entity wrapping a string value but it didn't work either.



      Does anybody knows what I'm doing wrong? Why for the Countries it's working and for the prefixes not?



      I use PropertyChanged.Fody.



      Thanks!







      c# mvvmcross selecteditem mvxbind mvxspinner






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 26 '18 at 7:04







      jcasas

















      asked Nov 21 '18 at 9:11









      jcasasjcasas

      6910




      6910
























          4 Answers
          4






          active

          oldest

          votes


















          1














          The error you are getting about null is because SelectedItem in the spinner does not allow null as a selected item. So if you want to display an empty item one solution is to add another fixed item that has an empty value, i.e. in the case of PhonePrefix you can set string.Empty and add it to the list of PhonePrefixes and in your Country you can set the first one as default or create a stub Country with name None for example and add it to the list of countries.



          Another point to take into account is that when you want to update the view you have to be sure that you are notifying it in the Main Thread. You are trying to update the PhonePrefix in a Task of another thread so the view does not get noticed.



          You should update PhonePrefix by doing:



          this.InvokeOnMainThread(() => PhonePrefix = userDataResult.user.country_code_phone;
          );



          This will take care of doing the set of PhonePrefix directly on the Main thread so your view will be notified correctly.





          Update



          After better looking at your question and own answer and seeing that you use PropertyChanged.Fody I can guess that the problem was in fact how you are assigning the PhonePrefix.



          PropertyChanged.Fody defaults behaviour is to add Equality Checking which replaces your property code



          public string PhonePrefix { get; set; }


          for something like



          private string _phonePrefix;
          public string PhonePrefix
          {
          get
          {
          return _phonePrefix;
          }
          set
          {
          if (!String.Equals(_phonePrefix, value))
          {
          _phonePrefix = value;
          OnPropertyChanged("PhonePrefix");
          }
          }
          }


          so when you do in the GetUserData():



          PhonePrefix = userDataResult.user.country_code_phone;


          and in the ProcessFormData()



          PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;


          PhonePrefix is not null or whitespace so it tries to reassign the same value but because fody adds the equality checking it does not get assigned again and therefore it does not raise the change of the value, so the view does not get notified.



          The assignation in GetUserData() I think it may be being done in another thread and that's why the view does not get notified.
          According of what you said Country does get updated in ProcessFormData() so in order to PhonePrefix to be updated too in that place you should only add the [DoNotCheckEquality] attribute to the property to avoid the equality checking and that should be all.



          [DoNotCheckEquality]
          public string PhonePrefix { get; set; }


          If it does not work you should add the invocation on the main thread too (I advise you to see in debug on which thread is the method being executed to see if you do need the invoke on main thread).



          HIH






          share|improve this answer


























          • I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

            – jcasas
            Nov 23 '18 at 6:57











          • In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

            – fmaccaroni
            Nov 23 '18 at 13:33






          • 1





            Thank you very much for the update. It really makes sense. Let me try!

            – jcasas
            Nov 27 '18 at 6:52











          • did it work? :D

            – fmaccaroni
            Nov 28 '18 at 13:05






          • 1





            It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

            – jcasas
            Nov 30 '18 at 10:09



















          0














          It does work, as PhonePrefix is set in GetUserData, also you should set Country. From your code Country is null, this is why you are getting the first item from the list selected or error also.






          share|improve this answer


























          • Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

            – jcasas
            Nov 23 '18 at 6:54



















          0














          Although it's a weird solution and still don't really understand why, I found a way to make it work. I have the feeling it has something to do with asynchronism.



          The problem was assignin the PhonePrefix property in the GetuserData() method and then reassign it in the ProcessFormData(). So now the code that works looks like that:



          private string _phonePrefix;
          public string PhonePrefix { get; set; }
          public string PhoneNumber { get; set; }
          public Country Country { get; set; } = new Country();

          public List<Country> Countries { get; set; } = new List<Country>();
          public List<string> Prefixes { get; set; } = new List<string>();

          public override async Task Initialize()
          {
          await base.Initialize();
          IsUserLogedIn = await _authService.IsUserLoggedIn();
          if (IsUserLogedIn)
          {
          //get user data from server, show user data
          await GetUserData();
          }

          //get countries, prefixes
          if (Countries.Count <= 0 || Prefixes.Count <= 0)
          {
          _registrationFormData = await _registrationService.GetRegistrationFormData();
          ProcessFormData();
          }

          AddValidationRules();
          }

          private async Task GetUserData()
          {
          try
          {
          var userDataResult = await _registrationService.GetLoggedInUserData();

          if (userDataResult != null)
          {
          if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
          {
          Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
          }
          else
          {

          //PhonePrefix = userDataResult.user.country_code_phone;
          //can't bind it here to the public binded property because the SelectedItem binding fails.
          //I first assign it to a private field and then use it in the ProcessFormData method
          _phonePrefix = userDataResult.user.country_code_phone;
          PhoneNumber = userDataResult.user.phone;
          Country.id = userDataResult.user.person.addresses[0].country_id;
          Country.name = userDataResult.user.person.addresses[0].country_name;
          }
          }
          }
          catch (Exception e)
          {
          Log.Error<RegistrationViewModel>("GetUserData", e);
          }
          }



          private void ProcessFormData()
          {
          if (_registrationFormData != null)
          {
          Countries = _registrationFormData.Countries?.ToList();
          var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
          Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

          var prefixes = new List<string>();
          if (Countries != null)
          {
          foreach (var country in Countries)
          {
          //spinner binding doesn't allow null values
          if (country.phone_prefix != null)
          {
          prefixes.Add(country.phone_prefix);
          }
          }
          }

          //we need to assign the binded Prefixes at once otherwise the binding for the SelectedItem fails
          Prefixes = prefixes;
          if (Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(_phonePrefix))
          {
          PhonePrefix = Prefixes?[0];
          }
          else
          {
          PhonePrefix = _phonePrefix;
          }
          }
          }


          Note the addition of a private property _phonePrefix to hold the phone prefix value in the GetUserData() and then assign it's value to the property that it's bind in the view, the PhonePrefix.



          Actually I can't really explain why this happens, so it would be nice if somebody could explain this behavior.






          share|improve this answer


























          • could you add where do you call GetUserData() and ProcessFormData()?

            – fmaccaroni
            Nov 23 '18 at 13:34











          • @fmaccaroni I updated the answer

            – jcasas
            Nov 23 '18 at 13:56











          • are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

            – fmaccaroni
            Nov 23 '18 at 15:30











          • Yes, I do. I will update the question stating that! Can't wait to hear your answer

            – jcasas
            Nov 26 '18 at 7:01











          • I've updated my answer with the explanation HIH

            – fmaccaroni
            Nov 26 '18 at 16:18





















          0














          The properties that you are using are not notifying the changes to view, for this you must use:




          string _phonePrefix;
          public string PhonePrefix
          {
          get => _phonePrefix;
          set => SetProperty(ref _phonePrefix, value);
          }






          share|improve this answer
























          • when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

            – fmaccaroni
            Nov 30 '18 at 12:21











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408601%2fbinding-to-mvxspinner-selecteditem-property-not-working%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          The error you are getting about null is because SelectedItem in the spinner does not allow null as a selected item. So if you want to display an empty item one solution is to add another fixed item that has an empty value, i.e. in the case of PhonePrefix you can set string.Empty and add it to the list of PhonePrefixes and in your Country you can set the first one as default or create a stub Country with name None for example and add it to the list of countries.



          Another point to take into account is that when you want to update the view you have to be sure that you are notifying it in the Main Thread. You are trying to update the PhonePrefix in a Task of another thread so the view does not get noticed.



          You should update PhonePrefix by doing:



          this.InvokeOnMainThread(() => PhonePrefix = userDataResult.user.country_code_phone;
          );



          This will take care of doing the set of PhonePrefix directly on the Main thread so your view will be notified correctly.





          Update



          After better looking at your question and own answer and seeing that you use PropertyChanged.Fody I can guess that the problem was in fact how you are assigning the PhonePrefix.



          PropertyChanged.Fody defaults behaviour is to add Equality Checking which replaces your property code



          public string PhonePrefix { get; set; }


          for something like



          private string _phonePrefix;
          public string PhonePrefix
          {
          get
          {
          return _phonePrefix;
          }
          set
          {
          if (!String.Equals(_phonePrefix, value))
          {
          _phonePrefix = value;
          OnPropertyChanged("PhonePrefix");
          }
          }
          }


          so when you do in the GetUserData():



          PhonePrefix = userDataResult.user.country_code_phone;


          and in the ProcessFormData()



          PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;


          PhonePrefix is not null or whitespace so it tries to reassign the same value but because fody adds the equality checking it does not get assigned again and therefore it does not raise the change of the value, so the view does not get notified.



          The assignation in GetUserData() I think it may be being done in another thread and that's why the view does not get notified.
          According of what you said Country does get updated in ProcessFormData() so in order to PhonePrefix to be updated too in that place you should only add the [DoNotCheckEquality] attribute to the property to avoid the equality checking and that should be all.



          [DoNotCheckEquality]
          public string PhonePrefix { get; set; }


          If it does not work you should add the invocation on the main thread too (I advise you to see in debug on which thread is the method being executed to see if you do need the invoke on main thread).



          HIH






          share|improve this answer


























          • I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

            – jcasas
            Nov 23 '18 at 6:57











          • In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

            – fmaccaroni
            Nov 23 '18 at 13:33






          • 1





            Thank you very much for the update. It really makes sense. Let me try!

            – jcasas
            Nov 27 '18 at 6:52











          • did it work? :D

            – fmaccaroni
            Nov 28 '18 at 13:05






          • 1





            It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

            – jcasas
            Nov 30 '18 at 10:09
















          1














          The error you are getting about null is because SelectedItem in the spinner does not allow null as a selected item. So if you want to display an empty item one solution is to add another fixed item that has an empty value, i.e. in the case of PhonePrefix you can set string.Empty and add it to the list of PhonePrefixes and in your Country you can set the first one as default or create a stub Country with name None for example and add it to the list of countries.



          Another point to take into account is that when you want to update the view you have to be sure that you are notifying it in the Main Thread. You are trying to update the PhonePrefix in a Task of another thread so the view does not get noticed.



          You should update PhonePrefix by doing:



          this.InvokeOnMainThread(() => PhonePrefix = userDataResult.user.country_code_phone;
          );



          This will take care of doing the set of PhonePrefix directly on the Main thread so your view will be notified correctly.





          Update



          After better looking at your question and own answer and seeing that you use PropertyChanged.Fody I can guess that the problem was in fact how you are assigning the PhonePrefix.



          PropertyChanged.Fody defaults behaviour is to add Equality Checking which replaces your property code



          public string PhonePrefix { get; set; }


          for something like



          private string _phonePrefix;
          public string PhonePrefix
          {
          get
          {
          return _phonePrefix;
          }
          set
          {
          if (!String.Equals(_phonePrefix, value))
          {
          _phonePrefix = value;
          OnPropertyChanged("PhonePrefix");
          }
          }
          }


          so when you do in the GetUserData():



          PhonePrefix = userDataResult.user.country_code_phone;


          and in the ProcessFormData()



          PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;


          PhonePrefix is not null or whitespace so it tries to reassign the same value but because fody adds the equality checking it does not get assigned again and therefore it does not raise the change of the value, so the view does not get notified.



          The assignation in GetUserData() I think it may be being done in another thread and that's why the view does not get notified.
          According of what you said Country does get updated in ProcessFormData() so in order to PhonePrefix to be updated too in that place you should only add the [DoNotCheckEquality] attribute to the property to avoid the equality checking and that should be all.



          [DoNotCheckEquality]
          public string PhonePrefix { get; set; }


          If it does not work you should add the invocation on the main thread too (I advise you to see in debug on which thread is the method being executed to see if you do need the invoke on main thread).



          HIH






          share|improve this answer


























          • I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

            – jcasas
            Nov 23 '18 at 6:57











          • In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

            – fmaccaroni
            Nov 23 '18 at 13:33






          • 1





            Thank you very much for the update. It really makes sense. Let me try!

            – jcasas
            Nov 27 '18 at 6:52











          • did it work? :D

            – fmaccaroni
            Nov 28 '18 at 13:05






          • 1





            It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

            – jcasas
            Nov 30 '18 at 10:09














          1












          1








          1







          The error you are getting about null is because SelectedItem in the spinner does not allow null as a selected item. So if you want to display an empty item one solution is to add another fixed item that has an empty value, i.e. in the case of PhonePrefix you can set string.Empty and add it to the list of PhonePrefixes and in your Country you can set the first one as default or create a stub Country with name None for example and add it to the list of countries.



          Another point to take into account is that when you want to update the view you have to be sure that you are notifying it in the Main Thread. You are trying to update the PhonePrefix in a Task of another thread so the view does not get noticed.



          You should update PhonePrefix by doing:



          this.InvokeOnMainThread(() => PhonePrefix = userDataResult.user.country_code_phone;
          );



          This will take care of doing the set of PhonePrefix directly on the Main thread so your view will be notified correctly.





          Update



          After better looking at your question and own answer and seeing that you use PropertyChanged.Fody I can guess that the problem was in fact how you are assigning the PhonePrefix.



          PropertyChanged.Fody defaults behaviour is to add Equality Checking which replaces your property code



          public string PhonePrefix { get; set; }


          for something like



          private string _phonePrefix;
          public string PhonePrefix
          {
          get
          {
          return _phonePrefix;
          }
          set
          {
          if (!String.Equals(_phonePrefix, value))
          {
          _phonePrefix = value;
          OnPropertyChanged("PhonePrefix");
          }
          }
          }


          so when you do in the GetUserData():



          PhonePrefix = userDataResult.user.country_code_phone;


          and in the ProcessFormData()



          PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;


          PhonePrefix is not null or whitespace so it tries to reassign the same value but because fody adds the equality checking it does not get assigned again and therefore it does not raise the change of the value, so the view does not get notified.



          The assignation in GetUserData() I think it may be being done in another thread and that's why the view does not get notified.
          According of what you said Country does get updated in ProcessFormData() so in order to PhonePrefix to be updated too in that place you should only add the [DoNotCheckEquality] attribute to the property to avoid the equality checking and that should be all.



          [DoNotCheckEquality]
          public string PhonePrefix { get; set; }


          If it does not work you should add the invocation on the main thread too (I advise you to see in debug on which thread is the method being executed to see if you do need the invoke on main thread).



          HIH






          share|improve this answer















          The error you are getting about null is because SelectedItem in the spinner does not allow null as a selected item. So if you want to display an empty item one solution is to add another fixed item that has an empty value, i.e. in the case of PhonePrefix you can set string.Empty and add it to the list of PhonePrefixes and in your Country you can set the first one as default or create a stub Country with name None for example and add it to the list of countries.



          Another point to take into account is that when you want to update the view you have to be sure that you are notifying it in the Main Thread. You are trying to update the PhonePrefix in a Task of another thread so the view does not get noticed.



          You should update PhonePrefix by doing:



          this.InvokeOnMainThread(() => PhonePrefix = userDataResult.user.country_code_phone;
          );



          This will take care of doing the set of PhonePrefix directly on the Main thread so your view will be notified correctly.





          Update



          After better looking at your question and own answer and seeing that you use PropertyChanged.Fody I can guess that the problem was in fact how you are assigning the PhonePrefix.



          PropertyChanged.Fody defaults behaviour is to add Equality Checking which replaces your property code



          public string PhonePrefix { get; set; }


          for something like



          private string _phonePrefix;
          public string PhonePrefix
          {
          get
          {
          return _phonePrefix;
          }
          set
          {
          if (!String.Equals(_phonePrefix, value))
          {
          _phonePrefix = value;
          OnPropertyChanged("PhonePrefix");
          }
          }
          }


          so when you do in the GetUserData():



          PhonePrefix = userDataResult.user.country_code_phone;


          and in the ProcessFormData()



          PhonePrefix = Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(PhonePrefix) ? Prefixes?[0] : PhonePrefix;


          PhonePrefix is not null or whitespace so it tries to reassign the same value but because fody adds the equality checking it does not get assigned again and therefore it does not raise the change of the value, so the view does not get notified.



          The assignation in GetUserData() I think it may be being done in another thread and that's why the view does not get notified.
          According of what you said Country does get updated in ProcessFormData() so in order to PhonePrefix to be updated too in that place you should only add the [DoNotCheckEquality] attribute to the property to avoid the equality checking and that should be all.



          [DoNotCheckEquality]
          public string PhonePrefix { get; set; }


          If it does not work you should add the invocation on the main thread too (I advise you to see in debug on which thread is the method being executed to see if you do need the invoke on main thread).



          HIH







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 26 '18 at 16:18

























          answered Nov 21 '18 at 13:24









          fmaccaronifmaccaroni

          2,3801824




          2,3801824













          • I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

            – jcasas
            Nov 23 '18 at 6:57











          • In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

            – fmaccaroni
            Nov 23 '18 at 13:33






          • 1





            Thank you very much for the update. It really makes sense. Let me try!

            – jcasas
            Nov 27 '18 at 6:52











          • did it work? :D

            – fmaccaroni
            Nov 28 '18 at 13:05






          • 1





            It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

            – jcasas
            Nov 30 '18 at 10:09



















          • I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

            – jcasas
            Nov 23 '18 at 6:57











          • In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

            – fmaccaroni
            Nov 23 '18 at 13:33






          • 1





            Thank you very much for the update. It really makes sense. Let me try!

            – jcasas
            Nov 27 '18 at 6:52











          • did it work? :D

            – fmaccaroni
            Nov 28 '18 at 13:05






          • 1





            It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

            – jcasas
            Nov 30 '18 at 10:09

















          I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

          – jcasas
          Nov 23 '18 at 6:57





          I understand the error message. I never said I wanted to display an empty item in the solution. About the main thread point, it's not true, as the Country and Countries properties are bind properly in the other spinner.

          – jcasas
          Nov 23 '18 at 6:57













          In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

          – fmaccaroni
          Nov 23 '18 at 13:33





          In order the View to get updated you must do the notification in the Main Thread, as I don't know how you called GetUserData() I supposed that it was being done in a backgorund thread. Regarding that you never said you wanted to display an empty item in the solution I like giving more information in an answer that's why I give that explanation, cause maybe to you is not useful but to somebody else it might be. I'll try to see in your solution why it works

          – fmaccaroni
          Nov 23 '18 at 13:33




          1




          1





          Thank you very much for the update. It really makes sense. Let me try!

          – jcasas
          Nov 27 '18 at 6:52





          Thank you very much for the update. It really makes sense. Let me try!

          – jcasas
          Nov 27 '18 at 6:52













          did it work? :D

          – fmaccaroni
          Nov 28 '18 at 13:05





          did it work? :D

          – fmaccaroni
          Nov 28 '18 at 13:05




          1




          1





          It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

          – jcasas
          Nov 30 '18 at 10:09





          It did work! So I will need to be careful when assigning my view model properties next time. Thanks a lot!

          – jcasas
          Nov 30 '18 at 10:09













          0














          It does work, as PhonePrefix is set in GetUserData, also you should set Country. From your code Country is null, this is why you are getting the first item from the list selected or error also.






          share|improve this answer


























          • Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

            – jcasas
            Nov 23 '18 at 6:54
















          0














          It does work, as PhonePrefix is set in GetUserData, also you should set Country. From your code Country is null, this is why you are getting the first item from the list selected or error also.






          share|improve this answer


























          • Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

            – jcasas
            Nov 23 '18 at 6:54














          0












          0








          0







          It does work, as PhonePrefix is set in GetUserData, also you should set Country. From your code Country is null, this is why you are getting the first item from the list selected or error also.






          share|improve this answer















          It does work, as PhonePrefix is set in GetUserData, also you should set Country. From your code Country is null, this is why you are getting the first item from the list selected or error also.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 21 '18 at 13:12

























          answered Nov 21 '18 at 13:05









          NicolaeNicolae

          213




          213













          • Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

            – jcasas
            Nov 23 '18 at 6:54



















          • Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

            – jcasas
            Nov 23 '18 at 6:54

















          Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

          – jcasas
          Nov 23 '18 at 6:54





          Thanks for the answer but it was not related to the Country being null. I just forgot to put it in my simplified snippet. Countries and Country properties are bind properly and show no error

          – jcasas
          Nov 23 '18 at 6:54











          0














          Although it's a weird solution and still don't really understand why, I found a way to make it work. I have the feeling it has something to do with asynchronism.



          The problem was assignin the PhonePrefix property in the GetuserData() method and then reassign it in the ProcessFormData(). So now the code that works looks like that:



          private string _phonePrefix;
          public string PhonePrefix { get; set; }
          public string PhoneNumber { get; set; }
          public Country Country { get; set; } = new Country();

          public List<Country> Countries { get; set; } = new List<Country>();
          public List<string> Prefixes { get; set; } = new List<string>();

          public override async Task Initialize()
          {
          await base.Initialize();
          IsUserLogedIn = await _authService.IsUserLoggedIn();
          if (IsUserLogedIn)
          {
          //get user data from server, show user data
          await GetUserData();
          }

          //get countries, prefixes
          if (Countries.Count <= 0 || Prefixes.Count <= 0)
          {
          _registrationFormData = await _registrationService.GetRegistrationFormData();
          ProcessFormData();
          }

          AddValidationRules();
          }

          private async Task GetUserData()
          {
          try
          {
          var userDataResult = await _registrationService.GetLoggedInUserData();

          if (userDataResult != null)
          {
          if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
          {
          Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
          }
          else
          {

          //PhonePrefix = userDataResult.user.country_code_phone;
          //can't bind it here to the public binded property because the SelectedItem binding fails.
          //I first assign it to a private field and then use it in the ProcessFormData method
          _phonePrefix = userDataResult.user.country_code_phone;
          PhoneNumber = userDataResult.user.phone;
          Country.id = userDataResult.user.person.addresses[0].country_id;
          Country.name = userDataResult.user.person.addresses[0].country_name;
          }
          }
          }
          catch (Exception e)
          {
          Log.Error<RegistrationViewModel>("GetUserData", e);
          }
          }



          private void ProcessFormData()
          {
          if (_registrationFormData != null)
          {
          Countries = _registrationFormData.Countries?.ToList();
          var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
          Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

          var prefixes = new List<string>();
          if (Countries != null)
          {
          foreach (var country in Countries)
          {
          //spinner binding doesn't allow null values
          if (country.phone_prefix != null)
          {
          prefixes.Add(country.phone_prefix);
          }
          }
          }

          //we need to assign the binded Prefixes at once otherwise the binding for the SelectedItem fails
          Prefixes = prefixes;
          if (Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(_phonePrefix))
          {
          PhonePrefix = Prefixes?[0];
          }
          else
          {
          PhonePrefix = _phonePrefix;
          }
          }
          }


          Note the addition of a private property _phonePrefix to hold the phone prefix value in the GetUserData() and then assign it's value to the property that it's bind in the view, the PhonePrefix.



          Actually I can't really explain why this happens, so it would be nice if somebody could explain this behavior.






          share|improve this answer


























          • could you add where do you call GetUserData() and ProcessFormData()?

            – fmaccaroni
            Nov 23 '18 at 13:34











          • @fmaccaroni I updated the answer

            – jcasas
            Nov 23 '18 at 13:56











          • are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

            – fmaccaroni
            Nov 23 '18 at 15:30











          • Yes, I do. I will update the question stating that! Can't wait to hear your answer

            – jcasas
            Nov 26 '18 at 7:01











          • I've updated my answer with the explanation HIH

            – fmaccaroni
            Nov 26 '18 at 16:18


















          0














          Although it's a weird solution and still don't really understand why, I found a way to make it work. I have the feeling it has something to do with asynchronism.



          The problem was assignin the PhonePrefix property in the GetuserData() method and then reassign it in the ProcessFormData(). So now the code that works looks like that:



          private string _phonePrefix;
          public string PhonePrefix { get; set; }
          public string PhoneNumber { get; set; }
          public Country Country { get; set; } = new Country();

          public List<Country> Countries { get; set; } = new List<Country>();
          public List<string> Prefixes { get; set; } = new List<string>();

          public override async Task Initialize()
          {
          await base.Initialize();
          IsUserLogedIn = await _authService.IsUserLoggedIn();
          if (IsUserLogedIn)
          {
          //get user data from server, show user data
          await GetUserData();
          }

          //get countries, prefixes
          if (Countries.Count <= 0 || Prefixes.Count <= 0)
          {
          _registrationFormData = await _registrationService.GetRegistrationFormData();
          ProcessFormData();
          }

          AddValidationRules();
          }

          private async Task GetUserData()
          {
          try
          {
          var userDataResult = await _registrationService.GetLoggedInUserData();

          if (userDataResult != null)
          {
          if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
          {
          Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
          }
          else
          {

          //PhonePrefix = userDataResult.user.country_code_phone;
          //can't bind it here to the public binded property because the SelectedItem binding fails.
          //I first assign it to a private field and then use it in the ProcessFormData method
          _phonePrefix = userDataResult.user.country_code_phone;
          PhoneNumber = userDataResult.user.phone;
          Country.id = userDataResult.user.person.addresses[0].country_id;
          Country.name = userDataResult.user.person.addresses[0].country_name;
          }
          }
          }
          catch (Exception e)
          {
          Log.Error<RegistrationViewModel>("GetUserData", e);
          }
          }



          private void ProcessFormData()
          {
          if (_registrationFormData != null)
          {
          Countries = _registrationFormData.Countries?.ToList();
          var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
          Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

          var prefixes = new List<string>();
          if (Countries != null)
          {
          foreach (var country in Countries)
          {
          //spinner binding doesn't allow null values
          if (country.phone_prefix != null)
          {
          prefixes.Add(country.phone_prefix);
          }
          }
          }

          //we need to assign the binded Prefixes at once otherwise the binding for the SelectedItem fails
          Prefixes = prefixes;
          if (Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(_phonePrefix))
          {
          PhonePrefix = Prefixes?[0];
          }
          else
          {
          PhonePrefix = _phonePrefix;
          }
          }
          }


          Note the addition of a private property _phonePrefix to hold the phone prefix value in the GetUserData() and then assign it's value to the property that it's bind in the view, the PhonePrefix.



          Actually I can't really explain why this happens, so it would be nice if somebody could explain this behavior.






          share|improve this answer


























          • could you add where do you call GetUserData() and ProcessFormData()?

            – fmaccaroni
            Nov 23 '18 at 13:34











          • @fmaccaroni I updated the answer

            – jcasas
            Nov 23 '18 at 13:56











          • are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

            – fmaccaroni
            Nov 23 '18 at 15:30











          • Yes, I do. I will update the question stating that! Can't wait to hear your answer

            – jcasas
            Nov 26 '18 at 7:01











          • I've updated my answer with the explanation HIH

            – fmaccaroni
            Nov 26 '18 at 16:18
















          0












          0








          0







          Although it's a weird solution and still don't really understand why, I found a way to make it work. I have the feeling it has something to do with asynchronism.



          The problem was assignin the PhonePrefix property in the GetuserData() method and then reassign it in the ProcessFormData(). So now the code that works looks like that:



          private string _phonePrefix;
          public string PhonePrefix { get; set; }
          public string PhoneNumber { get; set; }
          public Country Country { get; set; } = new Country();

          public List<Country> Countries { get; set; } = new List<Country>();
          public List<string> Prefixes { get; set; } = new List<string>();

          public override async Task Initialize()
          {
          await base.Initialize();
          IsUserLogedIn = await _authService.IsUserLoggedIn();
          if (IsUserLogedIn)
          {
          //get user data from server, show user data
          await GetUserData();
          }

          //get countries, prefixes
          if (Countries.Count <= 0 || Prefixes.Count <= 0)
          {
          _registrationFormData = await _registrationService.GetRegistrationFormData();
          ProcessFormData();
          }

          AddValidationRules();
          }

          private async Task GetUserData()
          {
          try
          {
          var userDataResult = await _registrationService.GetLoggedInUserData();

          if (userDataResult != null)
          {
          if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
          {
          Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
          }
          else
          {

          //PhonePrefix = userDataResult.user.country_code_phone;
          //can't bind it here to the public binded property because the SelectedItem binding fails.
          //I first assign it to a private field and then use it in the ProcessFormData method
          _phonePrefix = userDataResult.user.country_code_phone;
          PhoneNumber = userDataResult.user.phone;
          Country.id = userDataResult.user.person.addresses[0].country_id;
          Country.name = userDataResult.user.person.addresses[0].country_name;
          }
          }
          }
          catch (Exception e)
          {
          Log.Error<RegistrationViewModel>("GetUserData", e);
          }
          }



          private void ProcessFormData()
          {
          if (_registrationFormData != null)
          {
          Countries = _registrationFormData.Countries?.ToList();
          var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
          Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

          var prefixes = new List<string>();
          if (Countries != null)
          {
          foreach (var country in Countries)
          {
          //spinner binding doesn't allow null values
          if (country.phone_prefix != null)
          {
          prefixes.Add(country.phone_prefix);
          }
          }
          }

          //we need to assign the binded Prefixes at once otherwise the binding for the SelectedItem fails
          Prefixes = prefixes;
          if (Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(_phonePrefix))
          {
          PhonePrefix = Prefixes?[0];
          }
          else
          {
          PhonePrefix = _phonePrefix;
          }
          }
          }


          Note the addition of a private property _phonePrefix to hold the phone prefix value in the GetUserData() and then assign it's value to the property that it's bind in the view, the PhonePrefix.



          Actually I can't really explain why this happens, so it would be nice if somebody could explain this behavior.






          share|improve this answer















          Although it's a weird solution and still don't really understand why, I found a way to make it work. I have the feeling it has something to do with asynchronism.



          The problem was assignin the PhonePrefix property in the GetuserData() method and then reassign it in the ProcessFormData(). So now the code that works looks like that:



          private string _phonePrefix;
          public string PhonePrefix { get; set; }
          public string PhoneNumber { get; set; }
          public Country Country { get; set; } = new Country();

          public List<Country> Countries { get; set; } = new List<Country>();
          public List<string> Prefixes { get; set; } = new List<string>();

          public override async Task Initialize()
          {
          await base.Initialize();
          IsUserLogedIn = await _authService.IsUserLoggedIn();
          if (IsUserLogedIn)
          {
          //get user data from server, show user data
          await GetUserData();
          }

          //get countries, prefixes
          if (Countries.Count <= 0 || Prefixes.Count <= 0)
          {
          _registrationFormData = await _registrationService.GetRegistrationFormData();
          ProcessFormData();
          }

          AddValidationRules();
          }

          private async Task GetUserData()
          {
          try
          {
          var userDataResult = await _registrationService.GetLoggedInUserData();

          if (userDataResult != null)
          {
          if (!userDataResult.HTTPStatusCode.Equals(HttpStatusCode.OK))
          {
          Mvx.IoCProvider.Resolve<IUserDialogs>().Alert(userDataResult.Error?.Message);
          }
          else
          {

          //PhonePrefix = userDataResult.user.country_code_phone;
          //can't bind it here to the public binded property because the SelectedItem binding fails.
          //I first assign it to a private field and then use it in the ProcessFormData method
          _phonePrefix = userDataResult.user.country_code_phone;
          PhoneNumber = userDataResult.user.phone;
          Country.id = userDataResult.user.person.addresses[0].country_id;
          Country.name = userDataResult.user.person.addresses[0].country_name;
          }
          }
          }
          catch (Exception e)
          {
          Log.Error<RegistrationViewModel>("GetUserData", e);
          }
          }



          private void ProcessFormData()
          {
          if (_registrationFormData != null)
          {
          Countries = _registrationFormData.Countries?.ToList();
          var userCountry = Countries?.Where(c => c.id == Country?.id).FirstOrDefault();
          Country = IsUserLogedIn && Country != null ? userCountry : Countries?[0];

          var prefixes = new List<string>();
          if (Countries != null)
          {
          foreach (var country in Countries)
          {
          //spinner binding doesn't allow null values
          if (country.phone_prefix != null)
          {
          prefixes.Add(country.phone_prefix);
          }
          }
          }

          //we need to assign the binded Prefixes at once otherwise the binding for the SelectedItem fails
          Prefixes = prefixes;
          if (Prefixes.Count > 0 && !IsUserLogedIn && string.IsNullOrWhiteSpace(_phonePrefix))
          {
          PhonePrefix = Prefixes?[0];
          }
          else
          {
          PhonePrefix = _phonePrefix;
          }
          }
          }


          Note the addition of a private property _phonePrefix to hold the phone prefix value in the GetUserData() and then assign it's value to the property that it's bind in the view, the PhonePrefix.



          Actually I can't really explain why this happens, so it would be nice if somebody could explain this behavior.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 23 '18 at 13:55

























          answered Nov 23 '18 at 7:06









          jcasasjcasas

          6910




          6910













          • could you add where do you call GetUserData() and ProcessFormData()?

            – fmaccaroni
            Nov 23 '18 at 13:34











          • @fmaccaroni I updated the answer

            – jcasas
            Nov 23 '18 at 13:56











          • are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

            – fmaccaroni
            Nov 23 '18 at 15:30











          • Yes, I do. I will update the question stating that! Can't wait to hear your answer

            – jcasas
            Nov 26 '18 at 7:01











          • I've updated my answer with the explanation HIH

            – fmaccaroni
            Nov 26 '18 at 16:18





















          • could you add where do you call GetUserData() and ProcessFormData()?

            – fmaccaroni
            Nov 23 '18 at 13:34











          • @fmaccaroni I updated the answer

            – jcasas
            Nov 23 '18 at 13:56











          • are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

            – fmaccaroni
            Nov 23 '18 at 15:30











          • Yes, I do. I will update the question stating that! Can't wait to hear your answer

            – jcasas
            Nov 26 '18 at 7:01











          • I've updated my answer with the explanation HIH

            – fmaccaroni
            Nov 26 '18 at 16:18



















          could you add where do you call GetUserData() and ProcessFormData()?

          – fmaccaroni
          Nov 23 '18 at 13:34





          could you add where do you call GetUserData() and ProcessFormData()?

          – fmaccaroni
          Nov 23 '18 at 13:34













          @fmaccaroni I updated the answer

          – jcasas
          Nov 23 '18 at 13:56





          @fmaccaroni I updated the answer

          – jcasas
          Nov 23 '18 at 13:56













          are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

          – fmaccaroni
          Nov 23 '18 at 15:30





          are you using PropertyChanged.Fody? because if you do I think I know which was the problem at first and why it does work now

          – fmaccaroni
          Nov 23 '18 at 15:30













          Yes, I do. I will update the question stating that! Can't wait to hear your answer

          – jcasas
          Nov 26 '18 at 7:01





          Yes, I do. I will update the question stating that! Can't wait to hear your answer

          – jcasas
          Nov 26 '18 at 7:01













          I've updated my answer with the explanation HIH

          – fmaccaroni
          Nov 26 '18 at 16:18







          I've updated my answer with the explanation HIH

          – fmaccaroni
          Nov 26 '18 at 16:18













          0














          The properties that you are using are not notifying the changes to view, for this you must use:




          string _phonePrefix;
          public string PhonePrefix
          {
          get => _phonePrefix;
          set => SetProperty(ref _phonePrefix, value);
          }






          share|improve this answer
























          • when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

            – fmaccaroni
            Nov 30 '18 at 12:21
















          0














          The properties that you are using are not notifying the changes to view, for this you must use:




          string _phonePrefix;
          public string PhonePrefix
          {
          get => _phonePrefix;
          set => SetProperty(ref _phonePrefix, value);
          }






          share|improve this answer
























          • when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

            – fmaccaroni
            Nov 30 '18 at 12:21














          0












          0








          0







          The properties that you are using are not notifying the changes to view, for this you must use:




          string _phonePrefix;
          public string PhonePrefix
          {
          get => _phonePrefix;
          set => SetProperty(ref _phonePrefix, value);
          }






          share|improve this answer













          The properties that you are using are not notifying the changes to view, for this you must use:




          string _phonePrefix;
          public string PhonePrefix
          {
          get => _phonePrefix;
          set => SetProperty(ref _phonePrefix, value);
          }







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 27 '18 at 15:51









          Ornolis Vázquez ThompsonOrnolis Vázquez Thompson

          112




          112













          • when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

            – fmaccaroni
            Nov 30 '18 at 12:21



















          • when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

            – fmaccaroni
            Nov 30 '18 at 12:21

















          when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

          – fmaccaroni
          Nov 30 '18 at 12:21





          when you use github.com/Fody/PropertyChanged you don't need to do that. It automatically does it for you

          – fmaccaroni
          Nov 30 '18 at 12:21


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53408601%2fbinding-to-mvxspinner-selecteditem-property-not-working%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          'app-layout' is not a known element: how to share Component with different Modules

          android studio warns about leanback feature tag usage required on manifest while using Unity exported app?

          SQL update select statement