Home > OS >  DataBinding issue in Xamarin Forms
DataBinding issue in Xamarin Forms

Time:02-27

I have a new Xamarin Forms 5 app and I'm having trouble with data binding.

First, I display a message that tells the user how many items are in his list. Initially, this is 0. It's displayed by DisplayMessage property of the view model.

Then, the Init() method gets called and once the API call is finished, there are some items in MyList. I put break points to make sure that the API call works and I end up with some data in MyList property.

Because I change the value of message in my Init() method, I was expecting the message to change and display the number of items in the list but it's not changing even though I have some items in MyList.

I created a new ViewModel that looks like this:

public class MyViewModel : BaseViewModel
{
   public List<MyItem> MyList { get; set; } = new List<MyItem>();

   string message = "You have no items in your list... ";
  
   public string DisplayMessage
   {
       get => message;
       set
       {
           if(message == value)
               return;

           message = value;
           OnPropertyChanged();
       }
   }

   public async void Init()
   {
       var data = await _myService.GetData();
       
       if(data.Count > 0)
          message = $"You have {data.Count} items in your list!";

       MyList = data;
   }
}

My MainPage code behind looks like this:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
   MyViewModel _vm;
   MainPage()
   {
       InitializeComponent();
       _vm = new MyViewModel();
       this.BindingContext = _vm;
   }

   protected override void OnAppearing()
   {
      base.OnAppearing();
      _vm.Init();
   }
}

I didn't change anyting in the base view model, except I added my service and it looks like this:

public class BaseViewModel : INotifyPropertyChanged
{
    public IMyApiService MyApi => DependencyService.Get<IMyApiService>();

    bool isBusy = false;
    public bool IsBusy
    {
        get { return isBusy; }
        set { SetProperty(ref isBusy, value); }
    }

    string title = string.Empty;
    public string Title
    {
        get { return title; }
        set { SetProperty(ref title, value); }
    }
    protected bool SetProperty<T>(ref T backingStore, T value,
    [CallerMemberName] string propertyName = "",
    Action onChanged = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;
        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;
         changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

I'd appreciatae someone telling me where my mistake is. Thanks.

CodePudding user response:

Without seeing the Xaml, I can't 100% answer, but here are a couple of things I see:

  1. You are setting the "message" through the field, not the property. Since you are setting the field directly the OnPropertyChanged event isn't firing so the UI isn't getting notified that the value has changed.
  2. I am guessing you are binding "MyList" to some sort of CollectionView or something? If it's a readonly view, using a List is ok as the collection is never updated. However, if you plan on adding or removing items at runtime, it needs to be an "ObservableCollection" for the same reason as above, the UI isn't notified of new items in a List, but an ObservableCollection will notify the UI of changes to it, so it can update.
  3. Is what Jason mentions above in his comment. The MyList property should be setup like the other properties with the OnPropertyChanged.
  • Related