0

I'm trying to create an app which retrieves data from my api but I just don't know why the binding doesn't work. Here's the C# code

 public partial class PageData : ContentPage
{
    TodoList tdl { get; set; }
    public PageData()
    {
        tdl = new TodoList();
        this.BindingContext = tdl;
        InitializeComponent();
    }

    private async void ContentPage_Appearing(object sender, EventArgs e)
    {
        var httpClientHandler = new HttpClientHandler();
        httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
        HttpClient client = new HttpClient(httpClientHandler);
        var WebAPIUrl = @"http://192.168.x.xx:65xxx/api/data";
        var uri = new Uri(WebAPIUrl); 
        var response = await client.GetAsync(uri);
        if (response.IsSuccessStatusCode)
        {
            string responseBody = await response.Content.ReadAsStringAsync();
            var tmp = JsonConvert.DeserializeObject<List<TodoItem>>(responseBody);
            tdl.todoLists = new System.Collections.ObjectModel.ObservableCollection<TodoItem>(tmp);
        }
       // MyListView.ItemsSource = tdl.todoLists;
    }
}

It works when I use that last line I commented but it kind of feel like "cheating" as this isn't the best practice when using MVVM. I know there's a way around that but I just dont know what I'm doing wrong. thanks.

and here is the xaml code :

<ContentPage.Content>
    <ListView x:Name="MyListView" ItemsSource="{Binding todoLists}" RowHeight="70">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal" Spacing="20" Padding="5">
                        <StackLayout Orientation="Vertical">
                            <Label Text="To do: " FontAttributes="Bold" FontSize="17"></Label>
                            <Label Text="Is completed: "  FontAttributes="Bold" FontSize="17"></Label>
                        </StackLayout>
                        <StackLayout Orientation="Vertical">
                            <Label Text="{Binding name}" FontSize="17"></Label>
                            <Label Text="{Binding isCompleted}" FontSize="17"></Label>
                        </StackLayout>

                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage.Content>

here's my MVVM class :

using ExamenAout.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;

namespace ExamenAout.MVVM
{
    public class TodoList : INotifyPropertyChanged
    {
        private ObservableCollection<TodoItem> _todoLists { get; set; }

        public ObservableCollection<TodoItem> todoLists
        {
            get { return this._todoLists; }
            set
            {
                this._todoLists = value;
                OnPropertyRaised("todoList");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyRaised(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
    }
}

here's the TodoItem class :

    using System;
using System.Collections.Generic;
using System.Text;

namespace ExamenAout.Models
{
    public class TodoItem
    {
        public Guid userid { get; set; }
        public string name { get; set; }
        public bool isCompleted { get; set; }
    }
}
3
  • 2
    you are raising a property changed event passing the string "todoList" whereas your property is called "todoLists". probably where your issue is. Also recommend you use nameof rather than sending the string like that Commented Jan 13, 2021 at 19:11
  • oh my god, I'm so dumb! You're right! thanks a lot !! Commented Jan 13, 2021 at 19:17
  • 1
    I added an answer about your problem. Can you please accept it(click the ☑️ in the upper left corner of this answer ) so that we can help more people with same problem:). Commented Jan 15, 2021 at 1:28

2 Answers 2

1

Next time you can use nameof expression to prevent this mistake:) :

public ObservableCollection<TodoItem> todoLists
{
    get { return this._todoLists; }
    set
    {
        this._todoLists = value;
        OnPropertyRaised(nameof(todoLists));
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

To expand on Jack Hua's answer, you could also use CallerMemberNameAttribute. As the documentation explains:

Implementing the INotifyPropertyChanged interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed, so that the control can display the updated information. Without the CallerMemberName attribute, you must specify the property name as a literal.

You can use it as such:

using System.Runtime.CompilerServices;

private void OnPropertyRaised([CallerMemberName]string propertyName = "")
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

This makes it so the property's name you're setting is automatically passed

public ObservableCollection<TodoItem> todoLists
{
    get => _todoLists;
    set
    {
        _todoLists = value;
        OnPropertyRaised(); // You don't need to pass "todoLists" here
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.