Home > Back-end >  ObservableCollection not updating. What did I do wrong?
ObservableCollection not updating. What did I do wrong?

Time:10-09

I've got a problem with ObservableCollection in my Xamarin.Forms App. I am able to add values (I can read them out in the Debugger), but the view wont update.
I've tried quite a lot so far, but nothing seems to solve this problem.
Hope you can help:)
Here's my code:

private ObservableCollection<Transaction> transactions = new ObservableCollection<Transaction>();
public ObservableCollection<Transaction> Transactions
    {
        get { return transactions; }
        set
        {
            transactions = value;
            OnNotifyPropertyChanged();
        }
    }
public class Transaction:BaseViewModel
{
    private string name = null;
    private string price = null;
    private double numPrice = 0;
    private string date = null;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            OnNotifyPropertyChanged();
            name = value;
        }
    }
    public string Price
    {
        get
        {
            return price;
        }
        set
        {
            OnNotifyPropertyChanged();
            price = value;
        }
    }
    public double NumPrice
    {
        get
        {
            return numPrice;
        }
        set
        {
            OnNotifyPropertyChanged();
            numPrice = value;
        }
    }
    public string DateTime
    {
        get
        {
            return date;
        }
        set
        {
            OnNotifyPropertyChanged();
            date = value;
        }
    }
}

My BaseViewModel:

public class BaseViewModel : INotifyPropertyChanged
{
    
    protected BaseViewModel()
    {

    }

    #region Events
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    protected void OnNotifyPropertyChanged([CallerMemberName] string memberName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(memberName));
        }
    }
}

In XAML:

<ScrollView>
        <StackLayout BindableLayout.ItemsSource="{Binding Transactions}">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Frame BackgroundColor="#4D4D4D" CornerRadius="10">
                        <StackLayout Orientation="Horizontal">
                            <StackLayout>
                                <Label Text="{Binding Name}"/>
                                <Label Text="{Binding DateTime}"/>
                            </StackLayout>
                            <Label Text="{Binding Price}" FontSize="20"
                                   HorizontalOptions="EndAndExpand" VerticalOptions="CenterAndExpand" Margin="0,0,10,0" />
                        </StackLayout>
                    </Frame>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </ScrollView>

Thanks in advance

Edit: That's how I update the collection:

public void AddTransaction(string name, double price, DateTime dateTime)
    {
        Transactions.Add(new Transaction()
        {
            Name = name,
            Price = ($"-{price}€".Replace('.',',')),
            NumPrice = price,
            DateTime = dateTime.ToString("dd.MM.yyyy")
        });

    }

CodePudding user response:

You are probably missing the relevant code in your snippets, but my guess is that you are replacing the entire collection instead of updating it. Remove the getter from the Transactions property and make sure the member transactions is read-only. The "Observable" relates to the contents of the collection, not the instance itself.

CodePudding user response:

Please try the following and see if it works:

<ScrollView>
        <ListView ItemsSource="{Binding Transactions}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Frame BackgroundColor="#4D4D4D" CornerRadius="10">
                        <StackLayout Orientation="Horizontal">
                            <StackLayout>
                                <Label Text="{Binding Name}"/>
                                <Label Text="{Binding DateTime}"/>
                            </StackLayout>
                            <Label Text="{Binding Price}" FontSize="20"
                                   HorizontalOptions="EndAndExpand" VerticalOptions="CenterAndExpand" Margin="0,0,10,0" />
                        </StackLayout>
                    </Frame>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollView>

You could also substitute the ListView from my example with a CollectionView if it meets your needs better.

Important

Don't forget to change the order in all of your property setters, e.g.:

public string Name
    {
        get
        {
            return name;
        }
        set
        {
            if(name == value) return;
            name = value;
            OnNotifyPropertyChanged();
        }
    }

Alternative

Another thing you can do to make sure that your views get updated is calling OnNotifyPropertyChanged() on the collection when adding an item:

public void AddTransaction(string name, double price, DateTime dateTime)
    {
        Transactions.Add(new Transaction()
        {
            Name = name,
            Price = ($"-{price}€".Replace('.',',')),
            NumPrice = price,
            DateTime = dateTime.ToString("dd.MM.yyyy")
        });
        OnNotifyPropertyChanged(nameof(Transactions));
    }

Technically, this shouldn't be necessary on an ObservableCollection, but the problem might be related to having a BindableLayout attached to a StackLayout as is the case in your example.

  • Related