Reputation: 87
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; }
}
}
Upvotes: 0
Views: 221
Reputation: 3056
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
}
}
Upvotes: 1
Reputation: 15816
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));
}
}
Upvotes: 1